Version 2.12.0-271.0.dev

Merge commit 'c9da4cb2574d1fb4afa483605fb98cdc48c480bd' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/tool/smoke_test_quick.dart b/pkg/_fe_analyzer_shared/tool/smoke_test_quick.dart
index 2c7025c..c5cc34f 100644
--- a/pkg/_fe_analyzer_shared/tool/smoke_test_quick.dart
+++ b/pkg/_fe_analyzer_shared/tool/smoke_test_quick.dart
@@ -14,7 +14,7 @@
   futures.add(run("pkg/front_end/test/spelling_test_src_suite.dart",
       ["--", "spelling_test_src/_fe_analyzer_shared/..."]));
   futures.add(run(
-      "pkg/front_end/test/explicit_creation_test.dart", ["--shared-only"],
+      "pkg/front_end/test/explicit_creation_git_test.dart", ["--shared-only"],
       filter: false));
   futures.add(run("pkg/front_end/test/lint_suite.dart",
       ["--", "lint/_fe_analyzer_shared/..."]));
diff --git a/pkg/analysis_server/lib/src/computer/computer_outline.dart b/pkg/analysis_server/lib/src/computer/computer_outline.dart
index e36aed7..01a7d23 100644
--- a/pkg/analysis_server/lib/src/computer/computer_outline.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_outline.dart
@@ -237,23 +237,33 @@
   }
 
   Outline _newGenericTypeAliasOutline(GenericTypeAlias node) {
-    var functionType = node.functionType;
-    var returnType = functionType?.returnType;
     var nameNode = node.name;
     var name = nameNode.name;
-    var parameters = functionType?.parameters;
-    var parametersStr = _safeToSource(parameters);
-    var returnTypeStr = _safeToSource(returnType);
+
+    var aliasedType = node.type;
+    var aliasedFunctionType =
+        aliasedType is GenericFunctionType ? aliasedType : null;
+
     var element = Element(
-        ElementKind.FUNCTION_TYPE_ALIAS,
-        name,
-        Element.makeFlags(
-            isPrivate: Identifier.isPrivateName(name),
-            isDeprecated: _isDeprecated(node)),
-        location: _getLocationNode(nameNode),
-        parameters: parametersStr,
-        returnType: returnTypeStr,
-        typeParameters: _getTypeParametersStr(node.typeParameters));
+      aliasedFunctionType != null
+          ? ElementKind.FUNCTION_TYPE_ALIAS
+          : ElementKind.TYPE_ALIAS,
+      name,
+      Element.makeFlags(
+        isPrivate: Identifier.isPrivateName(name),
+        isDeprecated: _isDeprecated(node),
+      ),
+      aliasedType: _safeToSource(aliasedType),
+      location: _getLocationNode(nameNode),
+      parameters: aliasedFunctionType != null
+          ? _safeToSource(aliasedFunctionType.parameters)
+          : null,
+      returnType: aliasedFunctionType != null
+          ? _safeToSource(aliasedFunctionType.returnType)
+          : null,
+      typeParameters: _getTypeParametersStr(node.typeParameters),
+    );
+
     return _nodeOutline(node, element);
   }
 
diff --git a/pkg/analysis_server/test/src/computer/outline_computer_test.dart b/pkg/analysis_server/test/src/computer/outline_computer_test.dart
index 6bdeff5..7c3ca64 100644
--- a/pkg/analysis_server/test/src/computer/outline_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/outline_computer_test.dart
@@ -17,7 +17,8 @@
   });
 }
 
-class AbstractOutlineComputerTest extends AbstractContextTest {
+class AbstractOutlineComputerTest extends AbstractContextTest
+    with WithNonFunctionTypeAliasesMixin {
   String testPath;
   String testCode;
 
@@ -471,27 +472,7 @@
     }
   }
 
-  Future<void> test_genericTypeAlias_incomplete() async {
-    var unitOutline = await _computeOutline('''
-typedef F = Object;
-''');
-    var topOutlines = unitOutline.children;
-    expect(topOutlines, hasLength(1));
-    // F
-    var outline_F = topOutlines[0];
-    var element_F = outline_F.element;
-    expect(element_F.kind, ElementKind.FUNCTION_TYPE_ALIAS);
-    expect(element_F.name, 'F');
-    {
-      var location = element_F.location;
-      expect(location.offset, testCode.indexOf('F ='));
-      expect(location.length, 'F'.length);
-    }
-    expect(element_F.parameters, '');
-    expect(element_F.returnType, '');
-  }
-
-  Future<void> test_genericTypeAlias_minimal() async {
+  Future<void> test_genericTypeAlias_functionType() async {
     var unitOutline = await _computeOutline('''
 typedef F = void Function();
 ''');
@@ -507,11 +488,13 @@
       expect(location.offset, testCode.indexOf('F ='));
       expect(location.length, 'F'.length);
     }
+    expect(element_F.aliasedType, 'void Function()');
     expect(element_F.parameters, '()');
     expect(element_F.returnType, 'void');
+    expect(element_F.typeParameters, isNull);
   }
 
-  Future<void> test_genericTypeAlias_noReturnType() async {
+  Future<void> test_genericTypeAlias_functionType_noReturnType() async {
     var unitOutline = await _computeOutline('''
 typedef F = Function();
 ''');
@@ -527,8 +510,32 @@
       expect(location.offset, testCode.indexOf('F ='));
       expect(location.length, 'F'.length);
     }
+    expect(element_F.aliasedType, ' Function()');
     expect(element_F.parameters, '()');
     expect(element_F.returnType, '');
+    expect(element_F.typeParameters, isNull);
+  }
+
+  Future<void> test_genericTypeAlias_interfaceType() async {
+    var unitOutline = await _computeOutline('''
+typedef F<T> = Map<int, T>;
+''');
+    var topOutlines = unitOutline.children;
+    expect(topOutlines, hasLength(1));
+    // F
+    var outline_F = topOutlines[0];
+    var element_F = outline_F.element;
+    expect(element_F.kind, ElementKind.TYPE_ALIAS);
+    expect(element_F.name, 'F');
+    {
+      var location = element_F.location;
+      expect(location.offset, testCode.indexOf('F<T> ='));
+      expect(location.length, 'F'.length);
+    }
+    expect(element_F.aliasedType, 'Map<int, T>');
+    expect(element_F.parameters, isNull);
+    expect(element_F.returnType, isNull);
+    expect(element_F.typeParameters, '<T>');
   }
 
   Future<void> test_groupAndTest() async {
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
index 1df5522..821fe60 100644
--- a/pkg/analyzer/lib/src/dart/analysis/index.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -492,9 +492,6 @@
         elementKind == ElementKind.FUNCTION &&
             element is FunctionElement &&
             element.enclosingElement is ExecutableElement ||
-        elementKind == ElementKind.PARAMETER &&
-            element is ParameterElement &&
-            !element.isOptional ||
         false) {
       return;
     }
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index 1f5499e..3ba7ab9 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -17,7 +17,6 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(IndexTest);
-    defineReflectiveTests(IndexWithNonFunctionTypeAliasesTest);
   });
 }
 
@@ -35,7 +34,8 @@
 }
 
 @reflectiveTest
-class IndexTest extends PubPackageResolutionTest with _IndexMixin {
+class IndexTest extends PubPackageResolutionTest
+    with _IndexMixin, WithNonFunctionTypeAliasesMixin {
   test_fieldFormalParameter_noSuchField() async {
     await _indexTestUnit('''
 class B<T> {
@@ -128,6 +128,18 @@
     assertThat(elementObject).isExtendedAt('A {}', true, length: 0);
   }
 
+  test_isExtendedBy_ClassDeclaration_TypeAliasElement() async {
+    await _indexTestUnit('''
+class A<T> {}
+typedef B = A<int>;
+class C extends B {}
+''');
+    var B = findElement.typeAlias('B');
+    assertThat(B)
+      ..isExtendedAt('B {}', false)
+      ..isReferencedAt('B {}', false);
+  }
+
   test_isExtendedBy_ClassTypeAlias() async {
     await _indexTestUnit('''
 class A {}
@@ -180,6 +192,18 @@
       ..isReferencedAt('A {} // 2', true);
   }
 
+  test_isImplementedBy_ClassDeclaration_TypeAliasElement() async {
+    await _indexTestUnit('''
+class A<T> {}
+typedef B = A<int>;
+class C implements B {}
+''');
+    var B = findElement.typeAlias('B');
+    assertThat(B)
+      ..isImplementedAt('B {}', false)
+      ..isReferencedAt('B {}', false);
+  }
+
   test_isImplementedBy_ClassTypeAlias() async {
     await _indexTestUnit('''
 class A {} // 1
@@ -378,6 +402,18 @@
     assertThat(element).isInvokedAt('~a', true, length: 1);
   }
 
+  test_isMixedBy_ClassDeclaration_TypeAliasElement() async {
+    await _indexTestUnit('''
+class A<T> {}
+typedef B = A<int>;
+class C extends Object with B {}
+''');
+    var B = findElement.typeAlias('B');
+    assertThat(B)
+      ..isMixedInAt('B {}', false)
+      ..isReferencedAt('B {}', false);
+  }
+
   test_isMixedInBy_ClassDeclaration_class() async {
     await _indexTestUnit('''
 class A {} // 1
@@ -517,6 +553,16 @@
     assertThat(element).isReferencedAt('A();', false);
   }
 
+  test_isReferencedBy_ClassElement_inTypeAlias() async {
+    await _indexTestUnit('''
+class A<T> {}
+
+typedef B = A<int>;
+''');
+    assertThat(findElement.class_('A')).isReferencedAt('A<int', false);
+    assertThat(intElement).isReferencedAt('int>;', false);
+  }
+
   test_isReferencedBy_ClassElement_invocation_isQualified() async {
     newFile('$testPackageLibPath/lib.dart', content: '''
 class A {}
@@ -961,7 +1007,7 @@
 
   test_isReferencedBy_ParameterElement_genericFunctionType() async {
     await _indexTestUnit('''
-typedef F = void Function({int p});
+typedef F = void Function({int? p});
 
 void main(F f) {
   f(p: 0);
@@ -973,7 +1019,7 @@
 
   test_isReferencedBy_ParameterElement_genericFunctionType_call() async {
     await _indexTestUnit('''
-typedef F<T> = void Function({T test});
+typedef F<T> = void Function({T? test});
 
 main(F<int> f) {
   f.call(test: 0);
@@ -984,10 +1030,10 @@
 
   test_isReferencedBy_ParameterElement_multiplyDefined_generic() async {
     newFile('/test/lib/a.dart', content: r'''
-void foo<T>({T a}) {}
+void foo<T>({T? a}) {}
 ''');
     newFile('/test/lib/b.dart', content: r'''
-void foo<T>({T a}) {}
+void foo<T>({T? a}) {}
 ''');
     await _indexTestUnit(r"""
 import 'a.dart';
@@ -1000,10 +1046,10 @@
     // No exceptions.
   }
 
-  test_isReferencedBy_ParameterElement_named_ofConstructor_genericClass() async {
+  test_isReferencedBy_ParameterElement_optionalNamed_ofConstructor_genericClass() async {
     await _indexTestUnit('''
 class A<T> {
-  A({T test});
+  A({T? test});
 }
 
 main() {
@@ -1014,10 +1060,10 @@
     assertThat(element)..isReferencedAt('test: 0', true);
   }
 
-  test_isReferencedBy_ParameterElement_named_ofMethod_genericClass() async {
+  test_isReferencedBy_ParameterElement_optionalNamed_ofMethod_genericClass() async {
     await _indexTestUnit('''
 class A<T> {
-  void foo({T test}) {}
+  void foo({T? test}) {}
 }
 
 main(A<int> a) {
@@ -1028,6 +1074,18 @@
     assertThat(element)..isReferencedAt('test: 0', true);
   }
 
+  test_isReferencedBy_ParameterElement_optionalNamed_ofTopFunction() async {
+    await _indexTestUnit('''
+void foo({int? test}) {}
+
+void() {
+  foo(test: 0);
+}
+''');
+    Element element = findElement.parameter('test');
+    assertThat(element)..isReferencedAt('test: 0', true);
+  }
+
   test_isReferencedBy_ParameterElement_optionalPositional() async {
     await _indexTestUnit('''
 foo([p]) {
@@ -1043,6 +1101,18 @@
       ..isReferencedAt('1); // 2', true, length: 0);
   }
 
+  test_isReferencedBy_ParameterElement_requiredNamed_ofTopFunction() async {
+    await _indexTestUnit('''
+void foo({required int test}) {}
+
+void() {
+  foo(test: 0);
+}
+''');
+    Element element = findElement.parameter('test');
+    assertThat(element)..isReferencedAt('test: 0', true);
+  }
+
   test_isReferencedBy_PropertyAccessor_ofNamedExtension_instance() async {
     await _indexTestUnit('''
 extension E on int {
@@ -1173,6 +1243,33 @@
     assertThat(element).isReferencedAt('V;', true);
   }
 
+  test_isReferencedBy_TypeAliasElement() async {
+    await _indexTestUnit('''
+class A<T> {
+  static int field = 0;
+  static void method() {}
+}
+
+typedef B = A<int>;
+
+void f(B p) {
+  B v;
+  B(); // 2
+  B.field = 1;
+  B.field; // 3
+  B.method(); // 4
+}
+''');
+    var element = findElement.typeAlias('B');
+    assertThat(element)
+      ..isReferencedAt('B p) {', false)
+      ..isReferencedAt('B v;', false)
+      ..isReferencedAt('B(); // 2', false)
+      ..isReferencedAt('B.field = 1;', false)
+      ..isReferencedAt('B.field; // 3', false)
+      ..isReferencedAt('B.method(); // 4', false);
+  }
+
   test_isReferencedBy_typeInVariableList() async {
     await _indexTestUnit('''
 class A {}
@@ -1397,83 +1494,6 @@
   }
 }
 
-@reflectiveTest
-class IndexWithNonFunctionTypeAliasesTest extends PubPackageResolutionTest
-    with WithNonFunctionTypeAliasesMixin, _IndexMixin {
-  test_isExtendedBy_ClassDeclaration_TypeAliasElement() async {
-    await _indexTestUnit('''
-class A<T> {}
-typedef B = A<int>;
-class C extends B {}
-''');
-    var B = findElement.typeAlias('B');
-    assertThat(B)
-      ..isExtendedAt('B {}', false)
-      ..isReferencedAt('B {}', false);
-  }
-
-  test_isImplementedBy_ClassDeclaration_TypeAliasElement() async {
-    await _indexTestUnit('''
-class A<T> {}
-typedef B = A<int>;
-class C implements B {}
-''');
-    var B = findElement.typeAlias('B');
-    assertThat(B)
-      ..isImplementedAt('B {}', false)
-      ..isReferencedAt('B {}', false);
-  }
-
-  test_isMixedBy_ClassDeclaration_TypeAliasElement() async {
-    await _indexTestUnit('''
-class A<T> {}
-typedef B = A<int>;
-class C extends Object with B {}
-''');
-    var B = findElement.typeAlias('B');
-    assertThat(B)
-      ..isMixedInAt('B {}', false)
-      ..isReferencedAt('B {}', false);
-  }
-
-  test_isReferencedBy_ClassElement_inTypeAlias() async {
-    await _indexTestUnit('''
-class A<T> {}
-
-typedef B = A<int>;
-''');
-    assertThat(findElement.class_('A')).isReferencedAt('A<int', false);
-    assertThat(intElement).isReferencedAt('int>;', false);
-  }
-
-  test_isReferencedBy_TypeAliasElement() async {
-    await _indexTestUnit('''
-class A<T> {
-  static int field = 0;
-  static void method() {}
-}
-
-typedef B = A<int>;
-
-void f(B p) {
-  B v;
-  B(); // 2
-  B.field = 1;
-  B.field; // 3
-  B.method(); // 4
-}
-''');
-    var element = findElement.typeAlias('B');
-    assertThat(element)
-      ..isReferencedAt('B p) {', false)
-      ..isReferencedAt('B v;', false)
-      ..isReferencedAt('B(); // 2', false)
-      ..isReferencedAt('B.field = 1;', false)
-      ..isReferencedAt('B.field; // 3', false)
-      ..isReferencedAt('B.method(); // 4', false);
-  }
-}
-
 class _ElementIndexAssert {
   final _IndexMixin test;
   final Element element;
diff --git a/pkg/analyzer/test/src/diagnostics/non_constant_type_argument_test.dart b/pkg/analyzer/test/src/diagnostics/non_constant_type_argument_test.dart
index f783c71..b94d780 100644
--- a/pkg/analyzer/test/src/diagnostics/non_constant_type_argument_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/non_constant_type_argument_test.dart
@@ -9,53 +9,12 @@
 
 main() {
   defineReflectiveSuite(() {
-    defineReflectiveTests(NonConstantTypeArgumentNoWarningTest);
-    defineReflectiveTests(NonConstantTypeArgumentNoWarningTest2);
     defineReflectiveTests(NonConstantTypeArgumentTest);
     defineReflectiveTests(NonConstantTypeArgumentWarningTest);
   });
 }
 
 @reflectiveTest
-class NonConstantTypeArgumentNoWarningTest extends PubPackageResolutionTest {
-  test_asFunction_R() async {
-    await assertNoErrorsInCode(r'''
-import 'dart:ffi';
-
-class MyStruct extends Struct {
-  @Uint8()
-  int myField;
-}
-
-void main(){
-  final pointer = Pointer<MyStruct>.fromAddress(0);
-  pointer.ref.myField = 1;
-}
-''');
-  }
-}
-
-@reflectiveTest
-class NonConstantTypeArgumentNoWarningTest2 extends PubPackageResolutionTest {
-  test_asFunction_R() async {
-    await assertNoErrorsInCode(r'''
-import 'dart:ffi';
-
-class MyStruct extends Struct {
-  @Uint8()
-  int myField;
-}
-
-void main(){
-  final pointer = Pointer<MyStruct>.fromAddress(0)
-    ..ref.myField = 1;
-  print(pointer);
-}
-''');
-  }
-}
-
-@reflectiveTest
 class NonConstantTypeArgumentTest extends PubPackageResolutionTest {
   test_asFunction_R() async {
     await assertErrorsInCode(r'''
@@ -74,7 +33,40 @@
 
 @reflectiveTest
 class NonConstantTypeArgumentWarningTest extends PubPackageResolutionTest {
-  test_asFunction_R() async {
+  test_ref_class() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+
+class MyStruct extends Struct {
+  @Uint8()
+  int myField;
+}
+
+void main() {
+  final pointer = Pointer<MyStruct>.fromAddress(0);
+  pointer.ref.myField = 1;
+}
+''');
+  }
+
+  test_ref_class_cascade() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+
+class MyStruct extends Struct {
+  @Uint8()
+  int myField;
+}
+
+void main() {
+  final pointer = Pointer<MyStruct>.fromAddress(0)
+    ..ref.myField = 1;
+  print(pointer);
+}
+''');
+  }
+
+  test_ref_typeParameter() async {
     await assertErrorsInCode(r'''
 import 'dart:ffi';
 
diff --git a/pkg/front_end/test/binary_md_vm_tags_and_version_test.dart b/pkg/front_end/test/binary_md_vm_tags_and_version_git_test.dart
similarity index 100%
rename from pkg/front_end/test/binary_md_vm_tags_and_version_test.dart
rename to pkg/front_end/test/binary_md_vm_tags_and_version_git_test.dart
diff --git a/pkg/front_end/test/deps_test.dart b/pkg/front_end/test/deps_git_test.dart
similarity index 100%
rename from pkg/front_end/test/deps_test.dart
rename to pkg/front_end/test/deps_git_test.dart
diff --git a/pkg/front_end/test/explicit_creation_test.dart b/pkg/front_end/test/explicit_creation_git_test.dart
similarity index 100%
rename from pkg/front_end/test/explicit_creation_test.dart
rename to pkg/front_end/test/explicit_creation_git_test.dart
diff --git a/pkg/front_end/test/fasta/analyze_test.dart b/pkg/front_end/test/fasta/analyze_git_test.dart
similarity index 100%
rename from pkg/front_end/test/fasta/analyze_test.dart
rename to pkg/front_end/test/fasta/analyze_git_test.dart
diff --git a/pkg/front_end/test/fasta/analyze_src_with_lints_test.dart b/pkg/front_end/test/fasta/analyze_src_with_lints_git_test.dart
similarity index 100%
rename from pkg/front_end/test/fasta/analyze_src_with_lints_test.dart
rename to pkg/front_end/test/fasta/analyze_src_with_lints_git_test.dart
diff --git a/pkg/front_end/test/fasta/tool_test.dart b/pkg/front_end/test/fasta/tool_git_test.dart
similarity index 100%
rename from pkg/front_end/test/fasta/tool_test.dart
rename to pkg/front_end/test/fasta/tool_git_test.dart
diff --git a/pkg/front_end/test/language_versioning/language_versioning_up_to_date_test.dart b/pkg/front_end/test/language_versioning/language_versioning_up_to_date_git_test.dart
similarity index 100%
rename from pkg/front_end/test/language_versioning/language_versioning_up_to_date_test.dart
rename to pkg/front_end/test/language_versioning/language_versioning_up_to_date_git_test.dart
diff --git a/pkg/front_end/test/read_dill_from_binary_md_test.dart b/pkg/front_end/test/read_dill_from_binary_md_git_test.dart
similarity index 100%
rename from pkg/front_end/test/read_dill_from_binary_md_test.dart
rename to pkg/front_end/test/read_dill_from_binary_md_git_test.dart
diff --git a/pkg/front_end/test/unit_test_suites.dart b/pkg/front_end/test/unit_test_suites.dart
index fde99ac..3968363 100644
--- a/pkg/front_end/test/unit_test_suites.dart
+++ b/pkg/front_end/test/unit_test_suites.dart
@@ -1,432 +1,11 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE.md file.
 
 // @dart = 2.9
 
-import 'dart:async' show Timer;
-import 'dart:convert' show jsonEncode;
-import 'dart:io' show File, Platform, exitCode;
-import 'dart:isolate' show Isolate, ReceivePort, SendPort;
+// This is a work-around for the automagically selecting weak/strong mode.
+// By marking this file (the entry) as non-nnbd, it becomes weak mode which
+// is required because many of the imports are not (yet) nnbd.
 
-import 'package:args/args.dart' show ArgParser;
-import 'package:testing/src/chain.dart' show CreateContext, Result, Step;
-import 'package:testing/src/expectation.dart' show Expectation;
-import 'package:testing/src/log.dart' show Logger;
-import 'package:testing/src/run.dart' show runMe;
-import 'package:testing/src/suite.dart' as testing show Suite;
-import 'package:testing/src/test_description.dart' show TestDescription;
-
-import 'fasta/expression_suite.dart' as expression show createContext;
-import 'fasta/fast_strong_suite.dart' as fast_strong show createContext;
-import 'fasta/incremental_suite.dart' as incremental show createContext;
-import 'fasta/messages_suite.dart' as messages show createContext;
-import 'fasta/outline_suite.dart' as outline show createContext;
-import 'fasta/strong_tester.dart' as strong show createContext;
-import 'fasta/text_serialization_tester.dart' as text_serialization
-    show createContext;
-import 'fasta/textual_outline_suite.dart' as textual_outline show createContext;
-import 'fasta/weak_suite.dart' as weak show createContext;
-import 'incremental_bulk_compiler_smoke_suite.dart' as incremental_bulk_compiler
-    show createContext;
-import 'incremental_load_from_dill_suite.dart' as incremental_load
-    show createContext;
-import 'lint_suite.dart' as lint show createContext;
-import 'parser_suite.dart' as parser show createContext;
-import 'parser_all_suite.dart' as parserAll show createContext;
-import 'spelling_test_not_src_suite.dart' as spelling_not_src
-    show createContext;
-import 'spelling_test_src_suite.dart' as spelling_src show createContext;
-
-const suiteNamePrefix = "pkg/front_end/test";
-
-class Options {
-  final String configurationName;
-  final bool verbose;
-  final bool printFailureLog;
-  final Uri outputDirectory;
-  final String testFilter;
-  final List<String> environmentOptions;
-
-  Options(this.configurationName, this.verbose, this.printFailureLog,
-      this.outputDirectory, this.testFilter, this.environmentOptions);
-
-  static Options parse(List<String> args) {
-    var parser = new ArgParser()
-      ..addOption("named-configuration",
-          abbr: "n",
-          help: "configuration name to use for emitting json result files")
-      ..addOption("output-directory",
-          help: "directory to which results.json and logs.json are written")
-      ..addFlag("verbose",
-          abbr: "v", help: "print additional information", defaultsTo: false)
-      ..addFlag("print",
-          abbr: "p", help: "print failure logs", defaultsTo: false)
-      ..addMultiOption('environment',
-          abbr: 'D', help: "environment options for the test suite");
-    var parsedArguments = parser.parse(args);
-    String outputPath = parsedArguments["output-directory"] ?? ".";
-    Uri outputDirectory = Uri.base.resolveUri(Uri.directory(outputPath));
-    String filter;
-    if (parsedArguments.rest.length == 1) {
-      filter = parsedArguments.rest.single;
-      if (filter.startsWith("$suiteNamePrefix/")) {
-        filter = filter.substring(suiteNamePrefix.length + 1);
-      }
-    }
-    return Options(
-        parsedArguments["named-configuration"],
-        parsedArguments["verbose"],
-        parsedArguments["print"],
-        outputDirectory,
-        filter,
-        parsedArguments['environment']);
-  }
-}
-
-class ResultLogger implements Logger {
-  final String prefix;
-  final bool verbose;
-  final bool printFailureLog;
-  final SendPort resultsPort;
-  final SendPort logsPort;
-  final Map<String, Stopwatch> stopwatches = {};
-  final String configurationName;
-  final Set<String> seenTests = {};
-
-  ResultLogger(this.prefix, this.resultsPort, this.logsPort, this.verbose,
-      this.printFailureLog, this.configurationName);
-
-  String getTestName(TestDescription description) {
-    return "$prefix/${description.shortName}";
-  }
-
-  @override
-  void logMessage(Object message) {}
-
-  @override
-  void logNumberedLines(String text) {}
-
-  @override
-  void logProgress(String message) {}
-
-  @override
-  void logStepComplete(int completed, int failed, int total,
-      testing.Suite suite, TestDescription description, Step step) {}
-
-  @override
-  void logStepStart(int completed, int failed, int total, testing.Suite suite,
-      TestDescription description, Step step) {}
-
-  @override
-  void logSuiteStarted(testing.Suite suite) {}
-
-  @override
-  void logSuiteComplete(testing.Suite suite) {}
-
-  handleTestResult(TestDescription testDescription, Result result,
-      String fullSuiteName, bool matchedExpectations) {
-    String testName = getTestName(testDescription);
-    String suite = "pkg";
-    String shortTestName = testName.substring(suite.length + 1);
-    resultsPort.send(jsonEncode({
-      "name": testName,
-      "configuration": configurationName,
-      "suite": suite,
-      "test_name": shortTestName,
-      "time_ms": stopwatches[testName].elapsedMilliseconds,
-      "expected": "Pass",
-      "result": matchedExpectations ? "Pass" : "Fail",
-      "matches": matchedExpectations,
-    }));
-    if (!matchedExpectations) {
-      StringBuffer sb = new StringBuffer();
-      sb.write(result.log);
-      if (result.error != null) {
-        sb.write("\n\n${result.error}");
-      }
-      if (result.trace != null) {
-        sb.write("\n\n${result.trace}");
-      }
-      sb.write("\n\nTo re-run this test, run:");
-      sb.write("\n\n   dart pkg/front_end/test/unit_test_suites.dart -p "
-          "$testName");
-      if (result.autoFixCommand != null) {
-        sb.write("\n\nTo automatically update the test expectations, run:");
-        sb.write("\n\n   dart pkg/front_end/test/unit_test_suites.dart -p "
-            "$testName -D${result.autoFixCommand}");
-        if (result.canBeFixWithUpdateExpectations) {
-          sb.write('\n\nTo update test expectations for all tests at once, '
-              'run:');
-          sb.write('\n\n  dart pkg/front_end/tool/update_expectations.dart');
-          sb.write('\n\nNote that this takes a long time and should only be '
-              'used when many tests need updating.\n');
-        }
-      }
-      String failureLog = sb.toString();
-      String outcome = "${result.outcome}";
-      logsPort.send(jsonEncode({
-        "name": testName,
-        "configuration": configurationName,
-        "result": outcome,
-        "log": failureLog,
-      }));
-      if (printFailureLog) {
-        print('FAILED: $testName: $outcome');
-        print(failureLog);
-      }
-    }
-    if (verbose) {
-      String result = matchedExpectations ? "PASS" : "FAIL";
-      print("${testName}: ${result}");
-    }
-  }
-
-  void logTestStart(int completed, int failed, int total, testing.Suite suite,
-      TestDescription description) {
-    String name = getTestName(description);
-    stopwatches[name] = Stopwatch()..start();
-  }
-
-  @override
-  void logTestComplete(int completed, int failed, int total,
-      testing.Suite suite, TestDescription description) {}
-
-  @override
-  void logUncaughtError(error, StackTrace stackTrace) {}
-
-  void logExpectedResult(testing.Suite suite, TestDescription description,
-      Result result, Set<Expectation> expectedOutcomes) {
-    handleTestResult(description, result, prefix, true);
-  }
-
-  @override
-  void logUnexpectedResult(testing.Suite suite, TestDescription description,
-      Result result, Set<Expectation> expectedOutcomes) {
-    // The test framework (pkg/testing) calls the logger with an unexpected
-    // results a second time to create a summary. We ignore the second call
-    // here.
-    String testName = getTestName(description);
-    if (seenTests.contains(testName)) return;
-    seenTests.add(testName);
-    handleTestResult(description, result, prefix, false);
-  }
-}
-
-class Suite {
-  final String name;
-  final CreateContext createContext;
-  final String testingRootPath;
-  final String path;
-  final int shardCount;
-  final int shard;
-  final String prefix;
-
-  const Suite(this.name, this.createContext, this.testingRootPath,
-      {this.path, this.shardCount: 1, this.shard: 0, String prefix})
-      : prefix = prefix ?? name;
-}
-
-const List<Suite> suites = [
-  const Suite(
-      "fasta/expression", expression.createContext, "../../testing.json"),
-  const Suite("fasta/outline", outline.createContext, "../../testing.json"),
-  const Suite(
-      "fasta/fast_strong", fast_strong.createContext, "../../testing.json"),
-  const Suite(
-      "fasta/incremental", incremental.createContext, "../../testing.json"),
-  const Suite("fasta/messages", messages.createContext, "../../testing.json"),
-  const Suite("fasta/text_serialization1", text_serialization.createContext,
-      "../../testing.json",
-      path: "fasta/text_serialization_tester.dart",
-      shardCount: 4,
-      shard: 0,
-      prefix: "fasta/text_serialization"),
-  const Suite("fasta/text_serialization2", text_serialization.createContext,
-      "../../testing.json",
-      path: "fasta/text_serialization_tester.dart",
-      shardCount: 4,
-      shard: 1,
-      prefix: "fasta/text_serialization"),
-  const Suite("fasta/text_serialization3", text_serialization.createContext,
-      "../../testing.json",
-      path: "fasta/text_serialization_tester.dart",
-      shardCount: 4,
-      shard: 2,
-      prefix: "fasta/text_serialization"),
-  const Suite("fasta/text_serialization4", text_serialization.createContext,
-      "../../testing.json",
-      path: "fasta/text_serialization_tester.dart",
-      shardCount: 4,
-      shard: 3,
-      prefix: "fasta/text_serialization"),
-  const Suite("fasta/strong1", strong.createContext, "../../testing.json",
-      path: "fasta/strong_tester.dart",
-      shardCount: 4,
-      shard: 0,
-      prefix: "fasta/strong"),
-  const Suite("fasta/strong2", strong.createContext, "../../testing.json",
-      path: "fasta/strong_tester.dart",
-      shardCount: 4,
-      shard: 1,
-      prefix: "fasta/strong"),
-  const Suite("fasta/strong3", strong.createContext, "../../testing.json",
-      path: "fasta/strong_tester.dart",
-      shardCount: 4,
-      shard: 2,
-      prefix: "fasta/strong"),
-  const Suite("fasta/strong4", strong.createContext, "../../testing.json",
-      path: "fasta/strong_tester.dart",
-      shardCount: 4,
-      shard: 3,
-      prefix: "fasta/strong"),
-  const Suite("incremental_bulk_compiler_smoke",
-      incremental_bulk_compiler.createContext, "../testing.json"),
-  const Suite("incremental_load_from_dill", incremental_load.createContext,
-      "../testing.json"),
-  const Suite("lint", lint.createContext, "../testing.json"),
-  const Suite("parser", parser.createContext, "../testing.json"),
-  const Suite("parser_all", parserAll.createContext, "../testing.json"),
-  const Suite("spelling_test_not_src", spelling_not_src.createContext,
-      "../testing.json"),
-  const Suite(
-      "spelling_test_src", spelling_src.createContext, "../testing.json"),
-  const Suite("fasta/weak", weak.createContext, "../../testing.json"),
-  const Suite("fasta/textual_outline", textual_outline.createContext,
-      "../../testing.json"),
-];
-
-const Duration timeoutDuration = Duration(minutes: 30);
-
-class SuiteConfiguration {
-  final String name;
-  final SendPort resultsPort;
-  final SendPort logsPort;
-  final bool verbose;
-  final bool printFailureLog;
-  final String configurationName;
-  final String testFilter;
-  final List<String> environmentOptions;
-
-  const SuiteConfiguration(
-      this.name,
-      this.resultsPort,
-      this.logsPort,
-      this.verbose,
-      this.printFailureLog,
-      this.configurationName,
-      this.testFilter,
-      this.environmentOptions);
-}
-
-void runSuite(SuiteConfiguration configuration) {
-  Suite suite = suites.where((s) => s.name == configuration.name).single;
-  String name = suite.prefix;
-  String fullSuiteName = "$suiteNamePrefix/$name";
-  Uri suiteUri = Platform.script.resolve(suite.path ?? "${name}_suite.dart");
-  if (!new File.fromUri(suiteUri).existsSync()) {
-    throw "File doesn't exist: $suiteUri";
-  }
-  ResultLogger logger = ResultLogger(
-      fullSuiteName,
-      configuration.resultsPort,
-      configuration.logsPort,
-      configuration.verbose,
-      configuration.printFailureLog,
-      configuration.configurationName);
-  runMe(<String>[
-    if (configuration.testFilter != null) configuration.testFilter,
-    if (configuration.environmentOptions != null)
-      for (String option in configuration.environmentOptions) '-D${option}',
-  ], suite.createContext,
-      me: suiteUri,
-      configurationPath: suite.testingRootPath,
-      logger: logger,
-      shards: suite.shardCount,
-      shard: suite.shard);
-}
-
-void writeLinesToFile(Uri uri, List<String> lines) async {
-  await File.fromUri(uri).writeAsString(lines.map((line) => "$line\n").join());
-}
-
-main([List<String> arguments = const <String>[]]) async {
-  List<String> results = [];
-  List<String> logs = [];
-  Options options = Options.parse(arguments);
-  ReceivePort resultsPort = new ReceivePort()
-    ..listen((resultEntry) => results.add(resultEntry));
-  ReceivePort logsPort = new ReceivePort()
-    ..listen((logEntry) => logs.add(logEntry));
-  List<Future<bool>> futures = [];
-  // Run test suites and record the results and possible failure logs.
-  for (Suite suite in suites) {
-    String name = suite.name;
-    String filter = options.testFilter;
-    if (filter != null) {
-      // Skip suites that are not hit by the test filter, is there is one.
-      if (!filter.startsWith(suite.prefix)) {
-        continue;
-      }
-      // Remove the 'fasta/' from filters, if there, because it is not used
-      // in the name defined in testing.json.
-      if (filter.startsWith("fasta/")) {
-        filter = filter.substring("fasta/".length);
-      }
-    }
-    // Start the test suite in a new isolate.
-    ReceivePort exitPort = new ReceivePort();
-    SuiteConfiguration configuration = SuiteConfiguration(
-        name,
-        resultsPort.sendPort,
-        logsPort.sendPort,
-        options.verbose,
-        options.printFailureLog,
-        options.configurationName,
-        filter,
-        options.environmentOptions);
-    Future future = Future<bool>(() async {
-      Stopwatch stopwatch = Stopwatch()..start();
-      print("Running suite $name");
-      Isolate isolate = await Isolate.spawn<SuiteConfiguration>(
-          runSuite, configuration,
-          onExit: exitPort.sendPort);
-      bool timedOut = false;
-      Timer timer = Timer(timeoutDuration, () {
-        timedOut = true;
-        print("Suite $name timed out after "
-            "${timeoutDuration.inMilliseconds}ms");
-        isolate.kill(priority: Isolate.immediate);
-      });
-      await exitPort.first;
-      timer.cancel();
-      if (!timedOut) {
-        int seconds = stopwatch.elapsedMilliseconds ~/ 1000;
-        print("Suite $name finished (took ${seconds} seconds)");
-      }
-      return timedOut;
-    });
-    futures.add(future);
-  }
-  // Wait for isolates to terminate and clean up.
-  Iterable<bool> timeouts = await Future.wait(futures);
-  resultsPort.close();
-  logsPort.close();
-  // Write results.json and logs.json.
-  Uri resultJsonUri = options.outputDirectory.resolve("results.json");
-  Uri logsJsonUri = options.outputDirectory.resolve("logs.json");
-  await writeLinesToFile(resultJsonUri, results);
-  await writeLinesToFile(logsJsonUri, logs);
-  print("Log files written to ${resultJsonUri.toFilePath()} and"
-      " ${logsJsonUri.toFilePath()}");
-  // Return with exit code 1 if at least one suite timed out.
-  bool timeout = timeouts.any((timeout) => timeout);
-  if (timeout) {
-    exitCode = 1;
-  } else {
-    // The testing framework (package:testing) sets the exitCode to `1` if any
-    // test failed, so we reset it here to indicate that the test runner was
-    // successful.
-    exitCode = 0;
-  }
-}
+export 'unit_test_suites_impl.dart';
diff --git a/pkg/front_end/test/unit_test_suites_impl.dart b/pkg/front_end/test/unit_test_suites_impl.dart
new file mode 100644
index 0000000..fde99ac
--- /dev/null
+++ b/pkg/front_end/test/unit_test_suites_impl.dart
@@ -0,0 +1,432 @@
+// 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.md file.
+
+// @dart = 2.9
+
+import 'dart:async' show Timer;
+import 'dart:convert' show jsonEncode;
+import 'dart:io' show File, Platform, exitCode;
+import 'dart:isolate' show Isolate, ReceivePort, SendPort;
+
+import 'package:args/args.dart' show ArgParser;
+import 'package:testing/src/chain.dart' show CreateContext, Result, Step;
+import 'package:testing/src/expectation.dart' show Expectation;
+import 'package:testing/src/log.dart' show Logger;
+import 'package:testing/src/run.dart' show runMe;
+import 'package:testing/src/suite.dart' as testing show Suite;
+import 'package:testing/src/test_description.dart' show TestDescription;
+
+import 'fasta/expression_suite.dart' as expression show createContext;
+import 'fasta/fast_strong_suite.dart' as fast_strong show createContext;
+import 'fasta/incremental_suite.dart' as incremental show createContext;
+import 'fasta/messages_suite.dart' as messages show createContext;
+import 'fasta/outline_suite.dart' as outline show createContext;
+import 'fasta/strong_tester.dart' as strong show createContext;
+import 'fasta/text_serialization_tester.dart' as text_serialization
+    show createContext;
+import 'fasta/textual_outline_suite.dart' as textual_outline show createContext;
+import 'fasta/weak_suite.dart' as weak show createContext;
+import 'incremental_bulk_compiler_smoke_suite.dart' as incremental_bulk_compiler
+    show createContext;
+import 'incremental_load_from_dill_suite.dart' as incremental_load
+    show createContext;
+import 'lint_suite.dart' as lint show createContext;
+import 'parser_suite.dart' as parser show createContext;
+import 'parser_all_suite.dart' as parserAll show createContext;
+import 'spelling_test_not_src_suite.dart' as spelling_not_src
+    show createContext;
+import 'spelling_test_src_suite.dart' as spelling_src show createContext;
+
+const suiteNamePrefix = "pkg/front_end/test";
+
+class Options {
+  final String configurationName;
+  final bool verbose;
+  final bool printFailureLog;
+  final Uri outputDirectory;
+  final String testFilter;
+  final List<String> environmentOptions;
+
+  Options(this.configurationName, this.verbose, this.printFailureLog,
+      this.outputDirectory, this.testFilter, this.environmentOptions);
+
+  static Options parse(List<String> args) {
+    var parser = new ArgParser()
+      ..addOption("named-configuration",
+          abbr: "n",
+          help: "configuration name to use for emitting json result files")
+      ..addOption("output-directory",
+          help: "directory to which results.json and logs.json are written")
+      ..addFlag("verbose",
+          abbr: "v", help: "print additional information", defaultsTo: false)
+      ..addFlag("print",
+          abbr: "p", help: "print failure logs", defaultsTo: false)
+      ..addMultiOption('environment',
+          abbr: 'D', help: "environment options for the test suite");
+    var parsedArguments = parser.parse(args);
+    String outputPath = parsedArguments["output-directory"] ?? ".";
+    Uri outputDirectory = Uri.base.resolveUri(Uri.directory(outputPath));
+    String filter;
+    if (parsedArguments.rest.length == 1) {
+      filter = parsedArguments.rest.single;
+      if (filter.startsWith("$suiteNamePrefix/")) {
+        filter = filter.substring(suiteNamePrefix.length + 1);
+      }
+    }
+    return Options(
+        parsedArguments["named-configuration"],
+        parsedArguments["verbose"],
+        parsedArguments["print"],
+        outputDirectory,
+        filter,
+        parsedArguments['environment']);
+  }
+}
+
+class ResultLogger implements Logger {
+  final String prefix;
+  final bool verbose;
+  final bool printFailureLog;
+  final SendPort resultsPort;
+  final SendPort logsPort;
+  final Map<String, Stopwatch> stopwatches = {};
+  final String configurationName;
+  final Set<String> seenTests = {};
+
+  ResultLogger(this.prefix, this.resultsPort, this.logsPort, this.verbose,
+      this.printFailureLog, this.configurationName);
+
+  String getTestName(TestDescription description) {
+    return "$prefix/${description.shortName}";
+  }
+
+  @override
+  void logMessage(Object message) {}
+
+  @override
+  void logNumberedLines(String text) {}
+
+  @override
+  void logProgress(String message) {}
+
+  @override
+  void logStepComplete(int completed, int failed, int total,
+      testing.Suite suite, TestDescription description, Step step) {}
+
+  @override
+  void logStepStart(int completed, int failed, int total, testing.Suite suite,
+      TestDescription description, Step step) {}
+
+  @override
+  void logSuiteStarted(testing.Suite suite) {}
+
+  @override
+  void logSuiteComplete(testing.Suite suite) {}
+
+  handleTestResult(TestDescription testDescription, Result result,
+      String fullSuiteName, bool matchedExpectations) {
+    String testName = getTestName(testDescription);
+    String suite = "pkg";
+    String shortTestName = testName.substring(suite.length + 1);
+    resultsPort.send(jsonEncode({
+      "name": testName,
+      "configuration": configurationName,
+      "suite": suite,
+      "test_name": shortTestName,
+      "time_ms": stopwatches[testName].elapsedMilliseconds,
+      "expected": "Pass",
+      "result": matchedExpectations ? "Pass" : "Fail",
+      "matches": matchedExpectations,
+    }));
+    if (!matchedExpectations) {
+      StringBuffer sb = new StringBuffer();
+      sb.write(result.log);
+      if (result.error != null) {
+        sb.write("\n\n${result.error}");
+      }
+      if (result.trace != null) {
+        sb.write("\n\n${result.trace}");
+      }
+      sb.write("\n\nTo re-run this test, run:");
+      sb.write("\n\n   dart pkg/front_end/test/unit_test_suites.dart -p "
+          "$testName");
+      if (result.autoFixCommand != null) {
+        sb.write("\n\nTo automatically update the test expectations, run:");
+        sb.write("\n\n   dart pkg/front_end/test/unit_test_suites.dart -p "
+            "$testName -D${result.autoFixCommand}");
+        if (result.canBeFixWithUpdateExpectations) {
+          sb.write('\n\nTo update test expectations for all tests at once, '
+              'run:');
+          sb.write('\n\n  dart pkg/front_end/tool/update_expectations.dart');
+          sb.write('\n\nNote that this takes a long time and should only be '
+              'used when many tests need updating.\n');
+        }
+      }
+      String failureLog = sb.toString();
+      String outcome = "${result.outcome}";
+      logsPort.send(jsonEncode({
+        "name": testName,
+        "configuration": configurationName,
+        "result": outcome,
+        "log": failureLog,
+      }));
+      if (printFailureLog) {
+        print('FAILED: $testName: $outcome');
+        print(failureLog);
+      }
+    }
+    if (verbose) {
+      String result = matchedExpectations ? "PASS" : "FAIL";
+      print("${testName}: ${result}");
+    }
+  }
+
+  void logTestStart(int completed, int failed, int total, testing.Suite suite,
+      TestDescription description) {
+    String name = getTestName(description);
+    stopwatches[name] = Stopwatch()..start();
+  }
+
+  @override
+  void logTestComplete(int completed, int failed, int total,
+      testing.Suite suite, TestDescription description) {}
+
+  @override
+  void logUncaughtError(error, StackTrace stackTrace) {}
+
+  void logExpectedResult(testing.Suite suite, TestDescription description,
+      Result result, Set<Expectation> expectedOutcomes) {
+    handleTestResult(description, result, prefix, true);
+  }
+
+  @override
+  void logUnexpectedResult(testing.Suite suite, TestDescription description,
+      Result result, Set<Expectation> expectedOutcomes) {
+    // The test framework (pkg/testing) calls the logger with an unexpected
+    // results a second time to create a summary. We ignore the second call
+    // here.
+    String testName = getTestName(description);
+    if (seenTests.contains(testName)) return;
+    seenTests.add(testName);
+    handleTestResult(description, result, prefix, false);
+  }
+}
+
+class Suite {
+  final String name;
+  final CreateContext createContext;
+  final String testingRootPath;
+  final String path;
+  final int shardCount;
+  final int shard;
+  final String prefix;
+
+  const Suite(this.name, this.createContext, this.testingRootPath,
+      {this.path, this.shardCount: 1, this.shard: 0, String prefix})
+      : prefix = prefix ?? name;
+}
+
+const List<Suite> suites = [
+  const Suite(
+      "fasta/expression", expression.createContext, "../../testing.json"),
+  const Suite("fasta/outline", outline.createContext, "../../testing.json"),
+  const Suite(
+      "fasta/fast_strong", fast_strong.createContext, "../../testing.json"),
+  const Suite(
+      "fasta/incremental", incremental.createContext, "../../testing.json"),
+  const Suite("fasta/messages", messages.createContext, "../../testing.json"),
+  const Suite("fasta/text_serialization1", text_serialization.createContext,
+      "../../testing.json",
+      path: "fasta/text_serialization_tester.dart",
+      shardCount: 4,
+      shard: 0,
+      prefix: "fasta/text_serialization"),
+  const Suite("fasta/text_serialization2", text_serialization.createContext,
+      "../../testing.json",
+      path: "fasta/text_serialization_tester.dart",
+      shardCount: 4,
+      shard: 1,
+      prefix: "fasta/text_serialization"),
+  const Suite("fasta/text_serialization3", text_serialization.createContext,
+      "../../testing.json",
+      path: "fasta/text_serialization_tester.dart",
+      shardCount: 4,
+      shard: 2,
+      prefix: "fasta/text_serialization"),
+  const Suite("fasta/text_serialization4", text_serialization.createContext,
+      "../../testing.json",
+      path: "fasta/text_serialization_tester.dart",
+      shardCount: 4,
+      shard: 3,
+      prefix: "fasta/text_serialization"),
+  const Suite("fasta/strong1", strong.createContext, "../../testing.json",
+      path: "fasta/strong_tester.dart",
+      shardCount: 4,
+      shard: 0,
+      prefix: "fasta/strong"),
+  const Suite("fasta/strong2", strong.createContext, "../../testing.json",
+      path: "fasta/strong_tester.dart",
+      shardCount: 4,
+      shard: 1,
+      prefix: "fasta/strong"),
+  const Suite("fasta/strong3", strong.createContext, "../../testing.json",
+      path: "fasta/strong_tester.dart",
+      shardCount: 4,
+      shard: 2,
+      prefix: "fasta/strong"),
+  const Suite("fasta/strong4", strong.createContext, "../../testing.json",
+      path: "fasta/strong_tester.dart",
+      shardCount: 4,
+      shard: 3,
+      prefix: "fasta/strong"),
+  const Suite("incremental_bulk_compiler_smoke",
+      incremental_bulk_compiler.createContext, "../testing.json"),
+  const Suite("incremental_load_from_dill", incremental_load.createContext,
+      "../testing.json"),
+  const Suite("lint", lint.createContext, "../testing.json"),
+  const Suite("parser", parser.createContext, "../testing.json"),
+  const Suite("parser_all", parserAll.createContext, "../testing.json"),
+  const Suite("spelling_test_not_src", spelling_not_src.createContext,
+      "../testing.json"),
+  const Suite(
+      "spelling_test_src", spelling_src.createContext, "../testing.json"),
+  const Suite("fasta/weak", weak.createContext, "../../testing.json"),
+  const Suite("fasta/textual_outline", textual_outline.createContext,
+      "../../testing.json"),
+];
+
+const Duration timeoutDuration = Duration(minutes: 30);
+
+class SuiteConfiguration {
+  final String name;
+  final SendPort resultsPort;
+  final SendPort logsPort;
+  final bool verbose;
+  final bool printFailureLog;
+  final String configurationName;
+  final String testFilter;
+  final List<String> environmentOptions;
+
+  const SuiteConfiguration(
+      this.name,
+      this.resultsPort,
+      this.logsPort,
+      this.verbose,
+      this.printFailureLog,
+      this.configurationName,
+      this.testFilter,
+      this.environmentOptions);
+}
+
+void runSuite(SuiteConfiguration configuration) {
+  Suite suite = suites.where((s) => s.name == configuration.name).single;
+  String name = suite.prefix;
+  String fullSuiteName = "$suiteNamePrefix/$name";
+  Uri suiteUri = Platform.script.resolve(suite.path ?? "${name}_suite.dart");
+  if (!new File.fromUri(suiteUri).existsSync()) {
+    throw "File doesn't exist: $suiteUri";
+  }
+  ResultLogger logger = ResultLogger(
+      fullSuiteName,
+      configuration.resultsPort,
+      configuration.logsPort,
+      configuration.verbose,
+      configuration.printFailureLog,
+      configuration.configurationName);
+  runMe(<String>[
+    if (configuration.testFilter != null) configuration.testFilter,
+    if (configuration.environmentOptions != null)
+      for (String option in configuration.environmentOptions) '-D${option}',
+  ], suite.createContext,
+      me: suiteUri,
+      configurationPath: suite.testingRootPath,
+      logger: logger,
+      shards: suite.shardCount,
+      shard: suite.shard);
+}
+
+void writeLinesToFile(Uri uri, List<String> lines) async {
+  await File.fromUri(uri).writeAsString(lines.map((line) => "$line\n").join());
+}
+
+main([List<String> arguments = const <String>[]]) async {
+  List<String> results = [];
+  List<String> logs = [];
+  Options options = Options.parse(arguments);
+  ReceivePort resultsPort = new ReceivePort()
+    ..listen((resultEntry) => results.add(resultEntry));
+  ReceivePort logsPort = new ReceivePort()
+    ..listen((logEntry) => logs.add(logEntry));
+  List<Future<bool>> futures = [];
+  // Run test suites and record the results and possible failure logs.
+  for (Suite suite in suites) {
+    String name = suite.name;
+    String filter = options.testFilter;
+    if (filter != null) {
+      // Skip suites that are not hit by the test filter, is there is one.
+      if (!filter.startsWith(suite.prefix)) {
+        continue;
+      }
+      // Remove the 'fasta/' from filters, if there, because it is not used
+      // in the name defined in testing.json.
+      if (filter.startsWith("fasta/")) {
+        filter = filter.substring("fasta/".length);
+      }
+    }
+    // Start the test suite in a new isolate.
+    ReceivePort exitPort = new ReceivePort();
+    SuiteConfiguration configuration = SuiteConfiguration(
+        name,
+        resultsPort.sendPort,
+        logsPort.sendPort,
+        options.verbose,
+        options.printFailureLog,
+        options.configurationName,
+        filter,
+        options.environmentOptions);
+    Future future = Future<bool>(() async {
+      Stopwatch stopwatch = Stopwatch()..start();
+      print("Running suite $name");
+      Isolate isolate = await Isolate.spawn<SuiteConfiguration>(
+          runSuite, configuration,
+          onExit: exitPort.sendPort);
+      bool timedOut = false;
+      Timer timer = Timer(timeoutDuration, () {
+        timedOut = true;
+        print("Suite $name timed out after "
+            "${timeoutDuration.inMilliseconds}ms");
+        isolate.kill(priority: Isolate.immediate);
+      });
+      await exitPort.first;
+      timer.cancel();
+      if (!timedOut) {
+        int seconds = stopwatch.elapsedMilliseconds ~/ 1000;
+        print("Suite $name finished (took ${seconds} seconds)");
+      }
+      return timedOut;
+    });
+    futures.add(future);
+  }
+  // Wait for isolates to terminate and clean up.
+  Iterable<bool> timeouts = await Future.wait(futures);
+  resultsPort.close();
+  logsPort.close();
+  // Write results.json and logs.json.
+  Uri resultJsonUri = options.outputDirectory.resolve("results.json");
+  Uri logsJsonUri = options.outputDirectory.resolve("logs.json");
+  await writeLinesToFile(resultJsonUri, results);
+  await writeLinesToFile(logsJsonUri, logs);
+  print("Log files written to ${resultJsonUri.toFilePath()} and"
+      " ${logsJsonUri.toFilePath()}");
+  // Return with exit code 1 if at least one suite timed out.
+  bool timeout = timeouts.any((timeout) => timeout);
+  if (timeout) {
+    exitCode = 1;
+  } else {
+    // The testing framework (package:testing) sets the exitCode to `1` if any
+    // test failed, so we reset it here to indicate that the test runner was
+    // successful.
+    exitCode = 0;
+  }
+}
diff --git a/pkg/front_end/testing.json b/pkg/front_end/testing.json
index edd1e75..8bd4c7e 100644
--- a/pkg/front_end/testing.json
+++ b/pkg/front_end/testing.json
@@ -336,6 +336,7 @@
         "test/tool/reload\\.dart$",
         "test/type_labeler_test\\.dart$",
         "test/unit_test_suites\\.dart$",
+        "test/unit_test_suites_impl\\.dart$",
         "testcases/expression/main\\.dart$",
         "testcases/general/DeltaBlue\\.dart$",
         "testcases/general/annotation_variable_declaration\\.dart$",
diff --git a/pkg/front_end/tool/smoke_test_quick.dart b/pkg/front_end/tool/smoke_test_quick.dart
index 7427ee3..e942ef1 100644
--- a/pkg/front_end/tool/smoke_test_quick.dart
+++ b/pkg/front_end/tool/smoke_test_quick.dart
@@ -15,8 +15,8 @@
 main(List<String> args) async {
   Stopwatch stopwatch = new Stopwatch()..start();
   List<Future> futures = <Future>[];
-  futures.add(run(
-      "pkg/front_end/test/explicit_creation_test.dart", ["--front-end-only"],
+  futures.add(run("pkg/front_end/test/explicit_creation_git_test.dart",
+      ["--front-end-only"],
       filter: false));
   futures.add(run(
     "pkg/front_end/test/fasta/messages_suite.dart",
@@ -27,7 +27,7 @@
       ["--", "spelling_test_src/front_end/..."]));
   futures.add(
       run("pkg/front_end/test/lint_suite.dart", ["--", "lint/front_end/..."]));
-  futures.add(run("pkg/front_end/test/deps_test.dart", [], filter: false));
+  futures.add(run("pkg/front_end/test/deps_git_test.dart", [], filter: false));
   futures.add(run(
       "pkg/front_end/tool/_fasta/generate_experimental_flags_test.dart", [],
       filter: false));
diff --git a/pkg/pkg.status b/pkg/pkg.status
index da7fa09..18c8c4a 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -68,7 +68,7 @@
 dev_compiler/test/sourcemap/*: SkipByDesign # Skip sourcemap tests
 dev_compiler/test/sourcemap/testfiles/*: SkipByDesign # Skip dev_compiler codegen tests
 dev_compiler/test/worker/*: Skip # test needs fixes
-front_end/test/fasta/analyze_test: Pass, Slow
+front_end/test/fasta/analyze_git_test: Pass, Slow
 front_end/test/fasta/ast_builder_test: Pass, Slow
 front_end/test/fasta/bootstrap_test: Pass, Slow
 front_end/test/fasta/fast_legacy_test: Pass, Slow
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index 5fe1f7c..34e5f63 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -499,6 +499,9 @@
       __ CompareImmediate(TTSInternalRegs::kScratchReg, kNullCid);
       __ BranchIf(EQUAL, &is_subtype);
     }
+    // Never is a bottom type.
+    __ CompareImmediate(TTSInternalRegs::kScratchReg, kNeverCid);
+    __ BranchIf(EQUAL, &is_subtype);
     FlowGraphCompiler::GenerateCidRangesCheck(
         assembler, TTSInternalRegs::kScratchReg, ranges, &is_subtype,
         check_failed, true);
diff --git a/runtime/vm/type_testing_stubs_test.cc b/runtime/vm/type_testing_stubs_test.cc
index 04e4012..e00f107 100644
--- a/runtime/vm/type_testing_stubs_test.cc
+++ b/runtime/vm/type_testing_stubs_test.cc
@@ -407,6 +407,7 @@
       createI2() => I2();
       createBaseInt() => Base<int>();
       createBaseNull() => Base<Null>();
+      createBaseNever() => Base<Never>();
       createA() => A();
       createA1() => A1();
       createA2() => A2<int>();
@@ -433,6 +434,8 @@
       Object::Handle(Invoke(root_library, "createBaseInt"));
   const auto& obj_base_null =
       Object::Handle(Invoke(root_library, "createBaseNull"));
+  const auto& obj_base_never =
+      Object::Handle(Invoke(root_library, "createBaseNever"));
   const auto& obj_a = Object::Handle(Invoke(root_library, "createA"));
   const auto& obj_a1 = Object::Handle(Invoke(root_library, "createA1"));
   const auto& obj_a2 = Object::Handle(Invoke(root_library, "createA2"));
@@ -516,20 +519,42 @@
   RunTTSTest(obj_b2, type_base, tav_null, tav_null, ExpectLazilyHandledViaTTS,
              ExpectHandledViaTTS);
 
-  // Base<Null> as Base<int?>
-  // This is a regression test verifying that Null is included in
-  // class-id ranges for int?.
-  auto& type_int = Type::Handle(Type::IntType());
-  type_int = type_int.ToNullability(
+  // Base<Null|Never> as Base<int?>
+  // This is a regression test verifying that we don't fall through into
+  // runtime for Null and Never.
+  auto& type_nullable_int = Type::Handle(Type::IntType());
+  type_nullable_int = type_nullable_int.ToNullability(
       TestCase::IsNNBD() ? Nullability::kNullable : Nullability::kLegacy,
       Heap::kNew);
-  auto& tav_int = TypeArguments::Handle(TypeArguments::New(1));
-  tav_int.SetTypeAt(0, type_int);
-  CanonicalizeTAV(&tav_int);
-  auto& type_base_int = AbstractType::Handle(Type::New(class_base, tav_int));
-  FinalizeAndCanonicalize(&type_base_int);
-  RunTTSTest(obj_base_null, type_base_int, tav_null, tav_null,
+  auto& tav_nullable_int = TypeArguments::Handle(TypeArguments::New(1));
+  tav_nullable_int.SetTypeAt(0, type_nullable_int);
+  CanonicalizeTAV(&tav_nullable_int);
+  auto& type_base_nullable_int =
+      AbstractType::Handle(Type::New(class_base, tav_nullable_int));
+  FinalizeAndCanonicalize(&type_base_nullable_int);
+  RunTTSTest(obj_base_null, type_base_nullable_int, tav_null, tav_null,
              ExpectLazilyHandledViaTTS, ExpectHandledViaTTS);
+  RunTTSTest(obj_base_never, type_base_nullable_int, tav_null, tav_null,
+             ExpectLazilyHandledViaTTS, ExpectHandledViaTTS);
+
+  if (TestCase::IsNNBD()) {
+    // Base<Null|Never> as Base<int>
+    auto& type_int = Type::Handle(Type::IntType());
+    type_int = type_int.ToNullability(Nullability::kNonNullable, Heap::kNew);
+    auto& tav_int = TypeArguments::Handle(TypeArguments::New(1));
+    tav_int.SetTypeAt(0, type_int);
+    CanonicalizeTAV(&tav_int);
+    auto& type_base_int = Type::Handle(Type::New(class_base, tav_int));
+    type_base_int =
+        type_base_int.ToNullability(Nullability::kNonNullable, Heap::kNew);
+    FinalizeAndCanonicalize(&type_base_int);
+    if (IsolateGroup::Current()->null_safety()) {
+      RunTTSTest(obj_base_null, type_base_int, tav_null, tav_null,
+                 ExpectLazilyFailedViaTTS, ExpectFailedViaTTS);
+    }
+    RunTTSTest(obj_base_never, type_base_int, tav_null, tav_null,
+               ExpectLazilyHandledViaTTS, ExpectHandledViaTTS);
+  }
 
   // <...> as I2
   const auto& type_i2 = AbstractType::Handle(class_i2.RareType());
diff --git a/tools/VERSION b/tools/VERSION
index bc70d09..f6cc11d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 270
+PRERELEASE 271
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index f3980bc..12f746b 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -978,7 +978,7 @@
           "name": "unit tests",
           "arguments": [
             "-ncfe-unittest-asserts-${mode}-${system}",
-            "pkg/(kernel|front_end|fasta)"
+            "pkg/pkg/(kernel|front_end|fasta)/"
           ]
         },
         {