Version 2.12.0-225.0.dev

Merge commit '48503619f85c72ab4a522e4758746121ce85f797' into 'dev'
diff --git a/pkg/analysis_server/test/abstract_single_unit.dart b/pkg/analysis_server/test/abstract_single_unit.dart
index 504662a..006b6c1 100644
--- a/pkg/analysis_server/test/abstract_single_unit.dart
+++ b/pkg/analysis_server/test/abstract_single_unit.dart
@@ -4,7 +4,6 @@
 
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -12,6 +11,7 @@
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/error/hint_codes.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/test_utilities/find_element.dart';
 import 'package:analyzer/src/test_utilities/find_node.dart';
 import 'package:analyzer/src/test_utilities/platform.dart';
 import 'package:test/test.dart';
@@ -31,6 +31,7 @@
   CompilationUnitElement testUnitElement;
   LibraryElement testLibraryElement;
   FindNode findNode;
+  FindElement findElement;
 
   @override
   void addSource(String path, String content) {
@@ -48,10 +49,6 @@
     addSource(testFile, code);
   }
 
-  Element findElement(String name, [ElementKind kind]) {
-    return findChildElement(testUnitElement, name, kind);
-  }
-
   int findEnd(String search) {
     return findOffset(search) + search.length;
   }
@@ -61,16 +58,6 @@
     return findNodeAtString(search, (node) => node is SimpleIdentifier);
   }
 
-  /// Search the [testUnit] for the [LocalVariableElement] with the given
-  /// [name]. Fail if there is not exactly one such variable.
-  LocalVariableElement findLocalVariable(String name) {
-    var finder = _ElementsByNameFinder(name);
-    testUnit.accept(finder);
-    var localVariables = finder.elements.whereType<LocalVariableElement>();
-    expect(localVariables, hasLength(1));
-    return localVariables.single;
-  }
-
   AstNode findNodeAtOffset(int offset, [Predicate<AstNode> predicate]) {
     var result = NodeLocator(offset).searchWithin(testUnit);
     if (result != null && predicate != null) {
@@ -150,6 +137,7 @@
     testUnitElement = testUnit.declaredElement;
     testLibraryElement = testUnitElement.library;
     findNode = FindNode(testCode, testUnit);
+    findElement = FindElement(testUnit);
   }
 
   @override
@@ -158,17 +146,3 @@
     testFile = convertPath('/home/test/lib/test.dart');
   }
 }
-
-class _ElementsByNameFinder extends RecursiveAstVisitor<void> {
-  final String name;
-  final List<Element> elements = [];
-
-  _ElementsByNameFinder(this.name);
-
-  @override
-  void visitSimpleIdentifier(SimpleIdentifier node) {
-    if (node.name == name && node.inDeclarationContext()) {
-      elements.add(node.staticElement);
-    }
-  }
-}
diff --git a/pkg/analysis_server/test/services/correction/name_suggestion_test.dart b/pkg/analysis_server/test/services/correction/name_suggestion_test.dart
index 07e8f81..a4dce49 100644
--- a/pkg/analysis_server/test/services/correction/name_suggestion_test.dart
+++ b/pkg/analysis_server/test/services/correction/name_suggestion_test.dart
@@ -38,7 +38,7 @@
 }
 ''');
     var excluded = <String>{};
-    var expectedType = findLocalVariable('node').type;
+    var expectedType = findElement.localVar('node').type;
     Expression assignedExpression =
         findNodeAtString('null;', (node) => node is NullLiteral);
     var suggestions = getVariableNameSuggestionsForExpression(
@@ -52,7 +52,7 @@
   double res = 0.0;
 }
 ''');
-    var expectedType = findLocalVariable('res').type;
+    var expectedType = findElement.localVar('res').type;
     Expression assignedExpression = findNodeAtString('0.0;');
     // first choice for "double" is "d"
     expect(
@@ -72,7 +72,7 @@
   int res = 0;
 }
 ''');
-    var expectedType = findLocalVariable('res').type;
+    var expectedType = findElement.localVar('res').type;
     Expression assignedExpression = findNodeAtString('0;');
     // first choice for "int" is "i"
     expect(
@@ -92,7 +92,7 @@
   String res = 'abc';
 }
 ''');
-    var expectedType = findLocalVariable('res').type;
+    var expectedType = findElement.localVar('res').type;
     Expression assignedExpression = findNodeAtString("'abc';");
     // first choice for "String" is "s"
     expect(
diff --git a/pkg/analysis_server/test/services/correction/status_test.dart b/pkg/analysis_server/test/services/correction/status_test.dart
index 957e9cb..ac7f555 100644
--- a/pkg/analysis_server/test/services/correction/status_test.dart
+++ b/pkg/analysis_server/test/services/correction/status_test.dart
@@ -24,7 +24,7 @@
 class RefactoringLocationTest extends AbstractSingleUnitTest {
   Future<void> test_createLocation_forElement() async {
     await resolveTestCode('class MyClass {}');
-    var element = findElement('MyClass');
+    var element = findElement.class_('MyClass');
     // check
     var location = newLocation_fromElement(element);
     expect(location.file, testFile);
@@ -36,7 +36,7 @@
 
   Future<void> test_createLocation_forMatch() async {
     await resolveTestCode('class MyClass {}');
-    var element = findElement('MyClass');
+    var element = findElement.class_('MyClass');
     var sourceRange = range.elementName(element);
     SearchMatch match = SearchMatchImpl(
         element.source.fullName,
diff --git a/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart b/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
index fe8738b..5f334d4 100644
--- a/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
@@ -28,7 +28,10 @@
   var b = test;
 }
 ''');
-    _createRefactoring('test');
+    var element = findElement.topGet('test');
+    _createRefactoringForElement(
+      element,
+    );
     // apply refactoring
     return _assertSuccessfulRefactoring('''
 int test() => 42;
@@ -120,7 +123,8 @@
 main() {
 }
 ''');
-    _createRefactoring('test');
+    var element = findElement.topGet('test');
+    _createRefactoringForElement(element);
     // check conditions
     await _assertInitialConditions_fatal(
         'Only explicit getters can be converted to methods.');
@@ -141,12 +145,6 @@
     assertTestChangeResult(expectedCode);
   }
 
-  void _createRefactoring(String elementName) {
-    PropertyAccessorElement element =
-        findElement(elementName, ElementKind.GETTER);
-    _createRefactoringForElement(element);
-  }
-
   void _createRefactoringForElement(ExecutableElement element) {
     refactoring = ConvertGetterToMethodRefactoring(
         searchEngine, testAnalysisResult.session, element);
diff --git a/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart b/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
index 7195696..e80bb98 100644
--- a/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
@@ -30,7 +30,8 @@
   var b = test();
 }
 ''');
-    _createRefactoring('test');
+    var element = findElement.topFunction('test');
+    _createRefactoringForElement(element);
     // apply refactoring
     return _assertSuccessfulRefactoring('''
 int get test => 42;
@@ -124,7 +125,7 @@
   var b = test;
 }
 ''');
-    ExecutableElement element = findElement('test', ElementKind.GETTER);
+    var element = findElement.topGet('test');
     _createRefactoringForElement(element);
     // check conditions
     await _assertInitialConditions_fatal(
@@ -138,7 +139,8 @@
   var v = test(1);
 }
 ''');
-    _createRefactoring('test');
+    var element = findElement.topFunction('test');
+    _createRefactoringForElement(element);
     // check conditions
     await _assertInitialConditions_fatal(
         'Only methods without parameters can be converted to getters.');
@@ -164,7 +166,8 @@
   A.test();
 }
 ''');
-    _createRefactoring('test');
+    var element = findElement.constructor('test');
+    _createRefactoringForElement(element);
     // check conditions
     await _assertInitialConditions_fatal(
         'Only class methods or top-level functions can be converted to getters.');
@@ -174,7 +177,8 @@
     await indexTestUnit('''
 void test() {}
 ''');
-    _createRefactoring('test');
+    var element = findElement.topFunction('test');
+    _createRefactoringForElement(element);
     // check conditions
     await _assertInitialConditions_fatal(
         'Cannot convert function returning void.');
@@ -195,11 +199,6 @@
     assertTestChangeResult(expectedCode);
   }
 
-  void _createRefactoring(String elementName) {
-    ExecutableElement element = findElement(elementName);
-    _createRefactoringForElement(element);
-  }
-
   void _createRefactoringForElement(ExecutableElement element) {
     refactoring = ConvertMethodToGetterRefactoring(
         searchEngine, testAnalysisResult.session, element);
diff --git a/pkg/analysis_server/test/services/search/hierarchy_test.dart b/pkg/analysis_server/test/services/search/hierarchy_test.dart
index 4dbec50..e576ae2 100644
--- a/pkg/analysis_server/test/services/search/hierarchy_test.dart
+++ b/pkg/analysis_server/test/services/search/hierarchy_test.dart
@@ -41,12 +41,12 @@
 }
 ''');
     {
-      ClassElement classA = findElement('A');
+      var classA = findElement.class_('A');
       var members = getClassMembers(classA);
       expect(members.map((e) => e.name), unorderedEquals(['ma1', 'ma2']));
     }
     {
-      ClassElement classB = findElement('B');
+      var classB = findElement.class_('B');
       var members = getClassMembers(classB);
       expect(members.map((e) => e.name), unorderedEquals(['mb1', 'mb2']));
     }
@@ -61,8 +61,8 @@
   B() {}
 }
 ''');
-    ClassElement classA = findElement('A');
-    ClassElement classB = findElement('B');
+    var classA = findElement.class_('A');
+    var classB = findElement.class_('B');
     ClassMemberElement memberA = classA.constructors[0];
     ClassMemberElement memberB = classB.constructors[0];
     var futureA = getHierarchyMembers(searchEngine, memberA).then((members) {
@@ -89,10 +89,10 @@
   int foo;
 }
 ''');
-    ClassElement classA = findElement('A');
-    ClassElement classB = findElement('B');
-    ClassElement classC = findElement('C');
-    ClassElement classD = findElement('D');
+    var classA = findElement.class_('A');
+    var classB = findElement.class_('B');
+    var classC = findElement.class_('C');
+    var classD = findElement.class_('D');
     ClassMemberElement memberA = classA.fields[0];
     ClassMemberElement memberB = classB.fields[0];
     ClassMemberElement memberC = classC.fields[0];
@@ -124,9 +124,9 @@
   static set foo(x) {}
 }
 ''');
-    ClassElement classA = findElement('A');
-    ClassElement classB = findElement('B');
-    ClassElement classC = findElement('C');
+    var classA = findElement.class_('A');
+    var classB = findElement.class_('B');
+    var classC = findElement.class_('C');
     ClassMemberElement memberA = classA.fields[0];
     ClassMemberElement memberB = classB.fields[0];
     ClassMemberElement memberC = classC.fields[0];
@@ -162,11 +162,11 @@
   foo() {}
 }
 ''');
-    ClassElement classA = findElement('A');
-    ClassElement classB = findElement('B');
-    ClassElement classC = findElement('C');
-    ClassElement classD = findElement('D');
-    ClassElement classE = findElement('E');
+    var classA = findElement.class_('A');
+    var classB = findElement.class_('B');
+    var classC = findElement.class_('C');
+    var classD = findElement.class_('D');
+    var classE = findElement.class_('E');
     ClassMemberElement memberA = classA.methods[0];
     ClassMemberElement memberB = classB.methods[0];
     ClassMemberElement memberC = classC.methods[0];
@@ -199,8 +199,8 @@
   static foo() {}
 }
 ''');
-    ClassElement classA = findElement('A');
-    ClassElement classB = findElement('B');
+    var classA = findElement.class_('A');
+    var classB = findElement.class_('B');
     ClassMemberElement memberA = classA.methods[0];
     ClassMemberElement memberB = classB.methods[0];
     {
@@ -230,9 +230,9 @@
   foo() {}
 }
 ''');
-    ClassElement classA = findElement('A');
-    ClassElement classB = findElement('B');
-    ClassElement classD = findElement('D');
+    var classA = findElement.class_('A');
+    var classB = findElement.class_('B');
+    var classD = findElement.class_('D');
     ClassMemberElement memberA = classA.methods[0];
     ClassMemberElement memberB = classB.methods[0];
     ClassMemberElement memberD = classD.methods[0];
@@ -266,11 +266,11 @@
   foo({p}) {}
 }
 ''');
-    ClassElement classA = findElement('A');
-    ClassElement classB = findElement('B');
-    ClassElement classC = findElement('C');
-    ClassElement classD = findElement('D');
-    ClassElement classE = findElement('E');
+    var classA = findElement.class_('A');
+    var classB = findElement.class_('B');
+    var classC = findElement.class_('C');
+    var classD = findElement.class_('D');
+    var classE = findElement.class_('E');
     var parameterA = classA.methods[0].parameters[0];
     var parameterB = classB.methods[0].parameters[0];
     var parameterC = classC.methods[0].parameters[0];
@@ -313,7 +313,7 @@
   foo() {}
 }
 ''');
-    ClassElement classA = findElement('A');
+    var classA = findElement.class_('A');
     var parameterA = classA.methods[0].parameters[0];
 
     var result = await getHierarchyNamedParameters(searchEngine, parameterA);
@@ -330,7 +330,7 @@
   foo(p) {}
 }
 ''');
-    ClassElement classA = findElement('A');
+    var classA = findElement.class_('A');
     var parameterA = classA.methods[0].parameters[0];
 
     var result = await getHierarchyNamedParameters(searchEngine, parameterA);
@@ -352,7 +352,7 @@
 }
 ''');
     {
-      ClassElement classA = findElement('A');
+      var classA = findElement.class_('A');
       var members = getMembers(classA);
       expect(
           members.map((e) => e.name),
@@ -367,7 +367,7 @@
           ]));
     }
     {
-      ClassElement classB = findElement('B');
+      var classB = findElement.class_('B');
       var members = getMembers(classB);
       expect(
           members.map((e) => e.name),
@@ -395,12 +395,12 @@
 class E extends A with M {}
 class F implements A {}
 ''');
-    ClassElement classA = findElement('A');
-    ClassElement classB = findElement('B');
-    ClassElement classC = findElement('C');
-    ClassElement classD = findElement('D');
-    ClassElement classE = findElement('E');
-    ClassElement classF = findElement('F');
+    var classA = findElement.class_('A');
+    var classB = findElement.class_('B');
+    var classC = findElement.class_('C');
+    var classD = findElement.class_('D');
+    var classE = findElement.class_('E');
+    var classF = findElement.class_('F');
     var objectElement = classA.supertype.element;
     // Object
     {
@@ -451,14 +451,14 @@
 mixin M4 on M2 {}
 mixin M5 on A, C {}
 ''');
-    ClassElement a = findElement('A');
-    ClassElement b = findElement('B');
-    ClassElement c = findElement('C');
-    ClassElement m1 = findElement('M1');
-    ClassElement m2 = findElement('M2');
-    ClassElement m3 = findElement('M3');
-    ClassElement m4 = findElement('M4');
-    ClassElement m5 = findElement('M5');
+    var a = findElement.class_('A');
+    var b = findElement.class_('B');
+    var c = findElement.class_('C');
+    var m1 = findElement.mixin('M1');
+    var m2 = findElement.mixin('M2');
+    var m3 = findElement.mixin('M3');
+    var m4 = findElement.mixin('M4');
+    var m5 = findElement.mixin('M5');
     var object = a.supertype.element;
 
     _assertSuperClasses(object, []);
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
index 7e29218..40b6228 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
@@ -4590,6 +4590,44 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
+    Message Function(
+        DartType _type,
+        DartType _type2,
+        bool
+            isNonNullableByDefault)> templateSuperBoundedHint = const Template<
+        Message Function(
+            DartType _type, DartType _type2, bool isNonNullableByDefault)>(
+    messageTemplate:
+        r"""If you want '#type' to be a super-bounded type, note that the inverted type '#type2' must then satisfy its bounds, which it does not.""",
+    withArguments: _withArgumentsSuperBoundedHint);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+        Message Function(
+            DartType _type, DartType _type2, bool isNonNullableByDefault)>
+    codeSuperBoundedHint = const Code<
+            Message Function(
+                DartType _type, DartType _type2, bool isNonNullableByDefault)>(
+        "SuperBoundedHint",
+        severity: Severity.context);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsSuperBoundedHint(
+    DartType _type, DartType _type2, bool isNonNullableByDefault) {
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  List<Object> type2Parts = labeler.labelType(_type2);
+  String type = typeParts.join();
+  String type2 = type2Parts.join();
+  return new Message(codeSuperBoundedHint,
+      message:
+          """If you want '${type}' to be a super-bounded type, note that the inverted type '${type2}' must then satisfy its bounds, which it does not.""" +
+              labeler.originMessages,
+      arguments: {'type': _type, 'type2': _type2});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>
     templateSwitchExpressionNotAssignable = const Template<
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart b/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
index 76a901f..aca8810 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
@@ -35,6 +35,7 @@
         SymbolConstant,
         TearOffConstant,
         TreeNode,
+        Typedef,
         TypedefType,
         TypeLiteralConstant,
         TypeParameter,
@@ -142,7 +143,26 @@
   }
 
   void defaultDartType(DartType type) {}
-  void visitTypedefType(TypedefType node) {}
+
+  void visitTypedefType(TypedefType node) {
+    Typedef typedefNode = node.typedefNode;
+    result.add(nameForEntity(
+        typedefNode,
+        typedefNode.name,
+        typedefNode.enclosingLibrary.importUri,
+        typedefNode.enclosingLibrary.fileUri));
+    if (node.typeArguments.isNotEmpty) {
+      result.add("<");
+      bool first = true;
+      for (DartType typeArg in node.typeArguments) {
+        if (!first) result.add(", ");
+        typeArg.accept(this);
+        first = false;
+      }
+      result.add(">");
+    }
+    addNullability(node.nullability);
+  }
 
   void visitInvalidType(InvalidType node) {
     // TODO(askesc): Throw internal error if InvalidType appears in diagnostics.
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 6c3d8e8..7debb1a 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -418,8 +418,8 @@
             typeParameter.name,
             Variance.keywordString(variance));
       }
-      library.reportTypeArgumentIssue(
-          message, fileUri, fileOffset, typeParameter);
+      library.reportTypeArgumentIssue(message, fileUri, fileOffset,
+          typeParameter: typeParameter);
     }
   }
 
@@ -453,18 +453,26 @@
       bool inferred = libraryBuilder.inferredTypes.contains(argument);
       if (isGenericFunctionTypeOrAlias(argument)) {
         if (inferred) {
+          // Supertype can't be or contain super-bounded types, so null is
+          // passed for super-bounded hint here.
           libraryBuilder.reportTypeArgumentIssue(
               templateGenericFunctionTypeInferredAsActualTypeArgument
                   .withArguments(argument, library.isNonNullableByDefault),
               fileUri,
               charOffset,
-              null);
+              typeParameter: null,
+              superBoundedAttempt: null,
+              superBoundedAttemptInverted: null);
         } else {
+          // Supertype can't be or contain super-bounded types, so null is
+          // passed for super-bounded hint here.
           libraryBuilder.reportTypeArgumentIssue(
               messageGenericFunctionTypeUsedAsActualTypeArgument,
               fileUri,
               charOffset,
-              null);
+              typeParameter: null,
+              superBoundedAttempt: null,
+              superBoundedAttemptInverted: null);
         }
       } else {
         void reportProblem(
@@ -472,6 +480,8 @@
                     Message Function(DartType, DartType, String, String, String,
                         String, bool)>
                 template) {
+          // Supertype can't be or contain super-bounded types, so null is
+          // passed for super-bounded hint here.
           libraryBuilder.reportTypeArgumentIssue(
               template.withArguments(
                   argument,
@@ -483,7 +493,9 @@
                   library.isNonNullableByDefault),
               fileUri,
               charOffset,
-              typeParameter);
+              typeParameter: typeParameter,
+              superBoundedAttempt: null,
+              superBoundedAttemptInverted: null);
         }
 
         if (inferred) {
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index f46bba9..945cd98 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -3287,20 +3287,30 @@
         }
       }
 
-      reportTypeArgumentIssue(message, fileUri, offset, typeParameter);
+      reportTypeArgumentIssue(message, fileUri, offset,
+          typeParameter: typeParameter,
+          superBoundedAttempt: issue.enclosingType,
+          superBoundedAttemptInverted: issue.invertedType);
     }
   }
 
   void reportTypeArgumentIssue(Message message, Uri fileUri, int fileOffset,
-      TypeParameter typeParameter) {
+      {TypeParameter typeParameter,
+      DartType superBoundedAttempt,
+      DartType superBoundedAttemptInverted}) {
     List<LocatedMessage> context;
     if (typeParameter != null && typeParameter.fileOffset != -1) {
       // It looks like when parameters come from patch files, they don't
       // have a reportable location.
-      context = <LocatedMessage>[
-        messageIncorrectTypeArgumentVariable.withLocation(
-            typeParameter.location.file, typeParameter.fileOffset, noLength)
-      ];
+      (context ??= <LocatedMessage>[]).add(
+          messageIncorrectTypeArgumentVariable.withLocation(
+              typeParameter.location.file, typeParameter.fileOffset, noLength));
+    }
+    if (superBoundedAttemptInverted != null && superBoundedAttempt != null) {
+      (context ??= <LocatedMessage>[]).add(templateSuperBoundedHint
+          .withArguments(superBoundedAttempt, superBoundedAttemptInverted,
+              isNonNullableByDefault)
+          .withLocation(fileUri, fileOffset, noLength));
     }
     addProblem(message, fileOffset, noLength, fileUri, context: context);
   }
@@ -3389,7 +3399,7 @@
               messageGenericFunctionTypeUsedAsActualTypeArgument,
               fileUri,
               parameter.fileOffset,
-              null);
+              typeParameter: null);
         } else {
           reportTypeArgumentIssue(
               templateIncorrectTypeArgument.withArguments(
@@ -3400,7 +3410,9 @@
                   library.isNonNullableByDefault),
               fileUri,
               parameter.fileOffset,
-              typeParameter);
+              typeParameter: typeParameter,
+              superBoundedAttempt: issue.enclosingType,
+              superBoundedAttemptInverted: issue.invertedType);
         }
       }
     }
@@ -3461,7 +3473,7 @@
               messageGenericFunctionTypeUsedAsActualTypeArgument,
               fileUri,
               fileOffset,
-              null);
+              typeParameter: null);
         } else {
           reportTypeArgumentIssue(
               templateIncorrectTypeArgumentInReturnType.withArguments(
@@ -3472,7 +3484,9 @@
                   isNonNullableByDefault),
               fileUri,
               fileOffset,
-              typeParameter);
+              typeParameter: typeParameter,
+              superBoundedAttempt: issue.enclosingType,
+              superBoundedAttemptInverted: issue.invertedType);
         }
       }
     }
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index db4e95d..1f25446 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4139,6 +4139,10 @@
   template: "This is the type variable whose bound isn't conformed to."
   severity: CONTEXT
 
+SuperBoundedHint:
+  template: "If you want '#type' to be a super-bounded type, note that the inverted type '#type2' must then satisfy its bounds, which it does not."
+  severity: CONTEXT
+
 InferredPackageUri:
   template: "Interpreting this as package URI, '#uri'."
   severity: WARNING
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 040d1fe..4d427f4 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -649,6 +649,7 @@
 convenient
 conventional
 conventions
+conversion
 convert
 converted
 convertible
@@ -994,6 +995,7 @@
 enforcement
 engine
 engineers
+enhance
 enhancing
 enough
 ensure
@@ -1595,6 +1597,7 @@
 invalidation
 invariant
 invariantly
+inversion
 invert
 inverted
 investigate
diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt
index debea18..b0f4e5e 100644
--- a/pkg/front_end/test/spell_checking_list_messages.txt
+++ b/pkg/front_end/test/spell_checking_list_messages.txt
@@ -10,6 +10,7 @@
 # automatic tools might move it to the top of the file.
 
 JS
+adjusting
 argument(s)
 assigning
 b
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index c2db70b..915fdea 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -280,11 +280,25 @@
 foo13
 foo14
 foo15
+foo1a
+foo1b
 foo2
+foo2a
+foo2b
+foo3a
+foo3b
 foo4
+foo4a
+foo4b
 foo5
+foo5a
+foo5b
 foo6
+foo6a
+foo6b
 foo7
+foo7a
+foo7b
 foo8
 foo9
 foo\"bar'baz
diff --git a/pkg/front_end/testcases/nnbd/issue42546.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue42546.dart.outline.expect
index 8826a30..819fad7 100644
--- a/pkg/front_end/testcases/nnbd/issue42546.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/issue42546.dart.outline.expect
@@ -28,19 +28,19 @@
 
 
 Extra constant evaluation status:
-Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:664:13 -> SymbolConstant(#catchError)
-Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:664:13 -> ListConstant(const <Type*>[])
-Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:664:13 -> SymbolConstant(#test)
-Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:701:13 -> SymbolConstant(#whenComplete)
-Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:701:13 -> ListConstant(const <Type*>[])
-Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:701:13 -> InstanceConstant(const _ImmutableMap<Symbol*, dynamic>{_ImmutableMap._kvPairs: const <dynamic>[]})
-Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:728:13 -> SymbolConstant(#timeout)
-Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:728:13 -> ListConstant(const <Type*>[])
-Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:728:13 -> SymbolConstant(#onTimeout)
-Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:625:13 -> SymbolConstant(#then)
-Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:625:13 -> SymbolConstant(#onError)
-Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:712:13 -> SymbolConstant(#asStream)
-Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:712:13 -> ListConstant(const <Type*>[])
-Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:712:13 -> ListConstant(const <dynamic>[])
-Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:712:13 -> InstanceConstant(const _ImmutableMap<Symbol*, dynamic>{_ImmutableMap._kvPairs: const <dynamic>[]})
+Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:639:13 -> SymbolConstant(#catchError)
+Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:639:13 -> ListConstant(const <Type*>[])
+Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:639:13 -> SymbolConstant(#test)
+Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:675:13 -> SymbolConstant(#whenComplete)
+Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:675:13 -> ListConstant(const <Type*>[])
+Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:675:13 -> InstanceConstant(const _ImmutableMap<Symbol*, dynamic>{_ImmutableMap._kvPairs: const <dynamic>[]})
+Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:698:13 -> SymbolConstant(#timeout)
+Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:698:13 -> ListConstant(const <Type*>[])
+Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:698:13 -> SymbolConstant(#onTimeout)
+Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:602:13 -> SymbolConstant(#then)
+Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:602:13 -> SymbolConstant(#onError)
+Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:684:13 -> SymbolConstant(#asStream)
+Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:684:13 -> ListConstant(const <Type*>[])
+Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:684:13 -> ListConstant(const <dynamic>[])
+Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/async/future.dart:684:13 -> InstanceConstant(const _ImmutableMap<Symbol*, dynamic>{_ImmutableMap._kvPairs: const <dynamic>[]})
 Extra constant evaluation: evaluated: 61, effectively constant: 15
diff --git a/pkg/front_end/testcases/nnbd/super_bounded_hint.dart b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart
new file mode 100644
index 0000000..1fe49cb
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart
@@ -0,0 +1,80 @@
+// 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 file.
+
+// -------------------------------- Gives hint. -------------------------------
+
+class A<X> {}
+
+typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+
+foo1a(F<A<dynamic>, A<Never>> x) {}
+foo1b(F x) {}
+
+foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+foo2b<X extends F>() {}
+
+class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+
+class Foo3b<X extends F> {}
+
+F<A<dynamic>, A<Never>> foo4a() => throw 42;
+F foo4b() => throw 42;
+
+foo5a({required F<A<dynamic>, A<Never>> x}) {}
+foo5b({required F x}) {}
+
+foo6a() {
+  F<A<dynamic>, A<Never>> x;
+  for (F<A<dynamic>, A<Never>> x in []) {}
+  fooFoo1(F<A<dynamic>, A<Never>> x) {}
+  fooFoo2<X extends F<A<dynamic>, A<Never>>>() {}
+  F<A<dynamic>, A<Never>> fooFoo4() => throw 42;
+  fooFoo5({required F<A<dynamic>, A<Never>> x}) {}
+  fooFoo7([F<A<dynamic>, A<Never>>? x]) {}
+}
+
+foo6b() {
+  F x;
+  for (F x in []) {}
+  fooFoo1(F x) {}
+  fooFoo2<X extends F>() {}
+  F fooFoo4() => throw 42;
+  fooFoo5({required F x}) {}
+  fooFoo7([F? x]) {}
+}
+
+foo7a([F<A<dynamic>, A<Never>>? x]) {}
+foo7b([F? x]) {}
+
+// ---------------------------- Doesn't give hint. ----------------------------
+
+class B<X extends int> {}
+
+bar1(B<num> x) {}
+
+bar2<X extends B<num>>() {}
+
+class Bar3<X extends B<num>> {}
+
+B<num> bar4() => throw 42;
+
+bar5({required B<num> x}) {}
+
+bar6() {
+  B<num> x;
+  for (B<num> x in []) {}
+  barBar1(B<num> x) {}
+  barBar2<X extends B<num>>() {}
+  B<num> barBar4() => throw 42;
+  barBar5({required B<num> x}) {}
+  barBar7([B<num>? x]) {}
+  new B<dynamic>();
+  new A<B<dynamic>>();
+}
+
+bar7([B<num>? x]) {}
+
+class Bar8 extends B<dynamic> {}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.outline.expect b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.outline.expect
new file mode 100644
index 0000000..1d220b5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.outline.expect
@@ -0,0 +1,296 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Error: Generic type 'F' can't be used without type arguments in a type variable bound.
+// Try providing type arguments to 'F' here.
+// foo2b<X extends F>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: Bound of this variable references variable 'X' from the same declaration.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:19:13: Error: Generic type 'F' can't be used without type arguments in a type variable bound.
+// Try providing type arguments to 'F' here.
+// class Foo3b<X extends F> {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: Bound of this variable references variable 'X' from the same declaration.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:11:31: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo1a(F<A<dynamic>, A<Never>> x) {}
+//                               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:11:31: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo1a(F<A<dynamic>, A<Never>> x) {}
+//                               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:12:9: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo1b(F x) {}
+//         ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:12:9: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo1b(F x) {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:14:7: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:14:7: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+//       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo2b<X extends F>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo2b<X extends F>() {}
+//       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:17:13: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:17:13: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+//             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:21:30: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// F<A<dynamic>, A<Never>> foo4a() => throw 42;
+//                              ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:21:30: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// F<A<dynamic>, A<Never>> foo4a() => throw 42;
+//                              ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:22:8: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// F foo4b() => throw 42;
+//        ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:22:8: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// F foo4b() => throw 42;
+//        ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:24:41: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo5a({required F<A<dynamic>, A<Never>> x}) {}
+//                                         ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:24:41: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo5a({required F<A<dynamic>, A<Never>> x}) {}
+//                                         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:25:19: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo5b({required F x}) {}
+//                   ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:25:19: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo5b({required F x}) {}
+//                   ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:47:33: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo7a([F<A<dynamic>, A<Never>>? x]) {}
+//                                 ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:47:33: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo7a([F<A<dynamic>, A<Never>>? x]) {}
+//                                 ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:48:11: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo7b([F? x]) {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:48:11: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo7b([F? x]) {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:54:13: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar1(B<num> x) {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:56:6: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2<X extends B<num>>() {}
+//      ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:58:12: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar3<X extends B<num>> {}
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:60:12: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the return type.
+// Try changing type arguments so that they conform to the bounds.
+// B<num> bar4() => throw 42;
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:62:23: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar5({required B<num> x}) {}
+//                       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:76:15: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar7([B<num>? x]) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:78:7: Error: Type argument 'dynamic' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the supertype 'B' of class 'Bar8'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar8 extends B<dynamic> {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef F<X extends self::A<X> = self::A<dynamic>, contravariant Y extends self::A<Y> = self::A<Never>> = (Y) → X;
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    ;
+}
+class Foo3a<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>> extends core::Object {
+  synthetic constructor •() → self::Foo3a<self::Foo3a::X>
+    ;
+}
+class Foo3b<X extends (self::A<Never>) → self::A<dynamic> = dynamic> extends core::Object {
+  synthetic constructor •() → self::Foo3b<self::Foo3b::X>
+    ;
+}
+class B<X extends core::int = core::int> extends core::Object {
+  synthetic constructor •() → self::B<self::B::X>
+    ;
+}
+class Bar3<X extends self::B<core::num> = self::B<core::num>> extends core::Object {
+  synthetic constructor •() → self::Bar3<self::Bar3::X>
+    ;
+}
+class Bar8 extends self::B<dynamic> {
+  synthetic constructor •() → self::Bar8
+    ;
+}
+static method foo1a((self::A<Never>) → self::A<dynamic> x) → dynamic
+  ;
+static method foo1b((self::A<Never>) → self::A<dynamic> x) → dynamic
+  ;
+static method foo2a<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → dynamic
+  ;
+static method foo2b<X extends (self::A<Never>) → self::A<dynamic> = dynamic>() → dynamic
+  ;
+static method foo4a() → (self::A<Never>) → self::A<dynamic>
+  ;
+static method foo4b() → (self::A<Never>) → self::A<dynamic>
+  ;
+static method foo5a({required (self::A<Never>) → self::A<dynamic> x}) → dynamic
+  ;
+static method foo5b({required (self::A<Never>) → self::A<dynamic> x}) → dynamic
+  ;
+static method foo6a() → dynamic
+  ;
+static method foo6b() → dynamic
+  ;
+static method foo7a([(self::A<Never>) →? self::A<dynamic> x]) → dynamic
+  ;
+static method foo7b([(self::A<Never>) →? self::A<dynamic> x]) → dynamic
+  ;
+static method bar1(self::B<core::num> x) → dynamic
+  ;
+static method bar2<X extends self::B<core::num> = self::B<core::num>>() → dynamic
+  ;
+static method bar4() → self::B<core::num>
+  ;
+static method bar5({required self::B<core::num> x}) → dynamic
+  ;
+static method bar6() → dynamic
+  ;
+static method bar7([self::B<core::num>? x]) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.strong.expect b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.strong.expect
new file mode 100644
index 0000000..98725b8
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.strong.expect
@@ -0,0 +1,618 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Error: Generic type 'F' can't be used without type arguments in a type variable bound.
+// Try providing type arguments to 'F' here.
+// foo2b<X extends F>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: Bound of this variable references variable 'X' from the same declaration.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:19:13: Error: Generic type 'F' can't be used without type arguments in a type variable bound.
+// Try providing type arguments to 'F' here.
+// class Foo3b<X extends F> {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: Bound of this variable references variable 'X' from the same declaration.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:11:31: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo1a(F<A<dynamic>, A<Never>> x) {}
+//                               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:11:31: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo1a(F<A<dynamic>, A<Never>> x) {}
+//                               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:12:9: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo1b(F x) {}
+//         ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:12:9: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo1b(F x) {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:14:7: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:14:7: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+//       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo2b<X extends F>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo2b<X extends F>() {}
+//       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:17:13: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:17:13: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+//             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:21:30: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// F<A<dynamic>, A<Never>> foo4a() => throw 42;
+//                              ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:21:30: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// F<A<dynamic>, A<Never>> foo4a() => throw 42;
+//                              ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:22:8: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// F foo4b() => throw 42;
+//        ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:22:8: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// F foo4b() => throw 42;
+//        ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:24:41: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo5a({required F<A<dynamic>, A<Never>> x}) {}
+//                                         ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:24:41: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo5a({required F<A<dynamic>, A<Never>> x}) {}
+//                                         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:25:19: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo5b({required F x}) {}
+//                   ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:25:19: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo5b({required F x}) {}
+//                   ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:47:33: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo7a([F<A<dynamic>, A<Never>>? x]) {}
+//                                 ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:47:33: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo7a([F<A<dynamic>, A<Never>>? x]) {}
+//                                 ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:48:11: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo7b([F? x]) {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:48:11: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo7b([F? x]) {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:54:13: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar1(B<num> x) {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:56:6: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2<X extends B<num>>() {}
+//      ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:58:12: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar3<X extends B<num>> {}
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:60:12: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the return type.
+// Try changing type arguments so that they conform to the bounds.
+// B<num> bar4() => throw 42;
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:62:23: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar5({required B<num> x}) {}
+//                       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:76:15: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar7([B<num>? x]) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:78:7: Error: Type argument 'dynamic' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the supertype 'B' of class 'Bar8'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar8 extends B<dynamic> {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:28:27: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F<A<dynamic>, A<Never>> x;
+//                           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:28:27: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F<A<dynamic>, A<Never>> x;
+//                           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:32: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:32: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:37: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:37: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:30:35: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo1(F<A<dynamic>, A<Never>> x) {}
+//                                   ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:30:35: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo1(F<A<dynamic>, A<Never>> x) {}
+//                                   ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:31:11: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo2<X extends F<A<dynamic>, A<Never>>>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:31:11: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo2<X extends F<A<dynamic>, A<Never>>>() {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:32:34: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F<A<dynamic>, A<Never>> fooFoo4() => throw 42;
+//                                  ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:32:34: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F<A<dynamic>, A<Never>> fooFoo4() => throw 42;
+//                                  ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:33:45: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo5({required F<A<dynamic>, A<Never>> x}) {}
+//                                             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:33:45: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo5({required F<A<dynamic>, A<Never>> x}) {}
+//                                             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:34:37: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo7([F<A<dynamic>, A<Never>>? x]) {}
+//                                     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:34:37: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo7([F<A<dynamic>, A<Never>>? x]) {}
+//                                     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:38:5: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F x;
+//     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:38:5: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F x;
+//     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:10: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (F x in []) {}
+//          ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:10: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F x in []) {}
+//          ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:15: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (F x in []) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:15: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F x in []) {}
+//               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:40:13: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo1(F x) {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:40:13: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo1(F x) {}
+//             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:41:11: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo2<X extends F>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:41:11: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo2<X extends F>() {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:42:12: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F fooFoo4() => throw 42;
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:42:12: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F fooFoo4() => throw 42;
+//            ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:43:23: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo5({required F x}) {}
+//                       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:43:23: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo5({required F x}) {}
+//                       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:44:15: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo7([F? x]) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:44:15: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo7([F? x]) {}
+//               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:65:10: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   B<num> x;
+//          ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:66:15: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (B<num> x in []) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:72:7: Error: Type argument 'dynamic' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   new B<dynamic>();
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:66:20: Error: Inferred type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (B<num> x in []) {}
+//                    ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:67:18: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar1(B<num> x) {}
+//                  ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:68:11: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar2<X extends B<num>>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:69:17: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the return type.
+// Try changing type arguments so that they conform to the bounds.
+//   B<num> barBar4() => throw 42;
+//                 ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:70:28: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar5({required B<num> x}) {}
+//                            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:71:20: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar7([B<num>? x]) {}
+//                    ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef F<X extends self::A<X> = self::A<dynamic>, contravariant Y extends self::A<Y> = self::A<Never>> = (Y) → X;
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class Foo3a<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>> extends core::Object {
+  synthetic constructor •() → self::Foo3a<self::Foo3a::X>
+    : super core::Object::•()
+    ;
+}
+class Foo3b<X extends (self::A<Never>) → self::A<dynamic> = dynamic> extends core::Object {
+  synthetic constructor •() → self::Foo3b<self::Foo3b::X>
+    : super core::Object::•()
+    ;
+}
+class B<X extends core::int = core::int> extends core::Object {
+  synthetic constructor •() → self::B<self::B::X>
+    : super core::Object::•()
+    ;
+}
+class Bar3<X extends self::B<core::num> = self::B<core::num>> extends core::Object {
+  synthetic constructor •() → self::Bar3<self::Bar3::X>
+    : super core::Object::•()
+    ;
+}
+class Bar8 extends self::B<dynamic> {
+  synthetic constructor •() → self::Bar8
+    : super self::B::•()
+    ;
+}
+static method foo1a((self::A<Never>) → self::A<dynamic> x) → dynamic {}
+static method foo1b((self::A<Never>) → self::A<dynamic> x) → dynamic {}
+static method foo2a<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → dynamic {}
+static method foo2b<X extends (self::A<Never>) → self::A<dynamic> = dynamic>() → dynamic {}
+static method foo4a() → (self::A<Never>) → self::A<dynamic>
+  return throw 42;
+static method foo4b() → (self::A<Never>) → self::A<dynamic>
+  return throw 42;
+static method foo5a({required (self::A<Never>) → self::A<dynamic> x = #C1}) → dynamic {}
+static method foo5b({required (self::A<Never>) → self::A<dynamic> x = #C1}) → dynamic {}
+static method foo6a() → dynamic {
+  (self::A<Never>) → self::A<dynamic> x;
+  for ((self::A<Never>) → self::A<dynamic> x in <(self::A<Never>) → self::A<dynamic>>[]) {
+  }
+  function fooFoo1((self::A<Never>) → self::A<dynamic> x) → Null {}
+  function fooFoo2<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → Null {}
+  function fooFoo4() → (self::A<Never>) → self::A<dynamic>
+    return throw 42;
+  function fooFoo5({required (self::A<Never>) → self::A<dynamic> x = #C1}) → Null {}
+  function fooFoo7([(self::A<Never>) →? self::A<dynamic> x = #C1]) → Null {}
+}
+static method foo6b() → dynamic {
+  (self::A<Never>) → self::A<dynamic> x;
+  for ((self::A<Never>) → self::A<dynamic> x in <(self::A<Never>) → self::A<dynamic>>[]) {
+  }
+  function fooFoo1((self::A<Never>) → self::A<dynamic> x) → Null {}
+  function fooFoo2<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → Null {}
+  function fooFoo4() → (self::A<Never>) → self::A<dynamic>
+    return throw 42;
+  function fooFoo5({required (self::A<Never>) → self::A<dynamic> x = #C1}) → Null {}
+  function fooFoo7([(self::A<Never>) →? self::A<dynamic> x = #C1]) → Null {}
+}
+static method foo7a([(self::A<Never>) →? self::A<dynamic> x = #C1]) → dynamic {}
+static method foo7b([(self::A<Never>) →? self::A<dynamic> x = #C1]) → dynamic {}
+static method bar1(self::B<core::num> x) → dynamic {}
+static method bar2<X extends self::B<core::num> = self::B<core::num>>() → dynamic {}
+static method bar4() → self::B<core::num>
+  return throw 42;
+static method bar5({required self::B<core::num> x = #C1}) → dynamic {}
+static method bar6() → dynamic {
+  self::B<core::num> x;
+  for (self::B<core::num> x in <self::B<core::num>>[]) {
+  }
+  function barBar1(self::B<core::num> x) → Null {}
+  function barBar2<X extends self::B<core::num> = self::B<core::num>>() → Null {}
+  function barBar4() → self::B<core::num>
+    return throw 42;
+  function barBar5({required self::B<core::num> x = #C1}) → Null {}
+  function barBar7([self::B<core::num>? x = #C1]) → Null {}
+  new self::B::•<dynamic>();
+  new self::A::•<self::B<dynamic>>();
+}
+static method bar7([self::B<core::num>? x = #C1]) → dynamic {}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.strong.transformed.expect
new file mode 100644
index 0000000..edb2e83
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.strong.transformed.expect
@@ -0,0 +1,633 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Error: Generic type 'F' can't be used without type arguments in a type variable bound.
+// Try providing type arguments to 'F' here.
+// foo2b<X extends F>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: Bound of this variable references variable 'X' from the same declaration.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:19:13: Error: Generic type 'F' can't be used without type arguments in a type variable bound.
+// Try providing type arguments to 'F' here.
+// class Foo3b<X extends F> {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: Bound of this variable references variable 'X' from the same declaration.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:11:31: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo1a(F<A<dynamic>, A<Never>> x) {}
+//                               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:11:31: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo1a(F<A<dynamic>, A<Never>> x) {}
+//                               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:12:9: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo1b(F x) {}
+//         ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:12:9: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo1b(F x) {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:14:7: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:14:7: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+//       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo2b<X extends F>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo2b<X extends F>() {}
+//       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:17:13: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:17:13: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+//             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:21:30: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// F<A<dynamic>, A<Never>> foo4a() => throw 42;
+//                              ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:21:30: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// F<A<dynamic>, A<Never>> foo4a() => throw 42;
+//                              ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:22:8: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// F foo4b() => throw 42;
+//        ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:22:8: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// F foo4b() => throw 42;
+//        ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:24:41: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo5a({required F<A<dynamic>, A<Never>> x}) {}
+//                                         ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:24:41: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo5a({required F<A<dynamic>, A<Never>> x}) {}
+//                                         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:25:19: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo5b({required F x}) {}
+//                   ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:25:19: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo5b({required F x}) {}
+//                   ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:47:33: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo7a([F<A<dynamic>, A<Never>>? x]) {}
+//                                 ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:47:33: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo7a([F<A<dynamic>, A<Never>>? x]) {}
+//                                 ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:48:11: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo7b([F? x]) {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:48:11: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo7b([F? x]) {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:54:13: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar1(B<num> x) {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:56:6: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2<X extends B<num>>() {}
+//      ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:58:12: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar3<X extends B<num>> {}
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:60:12: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the return type.
+// Try changing type arguments so that they conform to the bounds.
+// B<num> bar4() => throw 42;
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:62:23: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar5({required B<num> x}) {}
+//                       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:76:15: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar7([B<num>? x]) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:78:7: Error: Type argument 'dynamic' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the supertype 'B' of class 'Bar8'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar8 extends B<dynamic> {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:28:27: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F<A<dynamic>, A<Never>> x;
+//                           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:28:27: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F<A<dynamic>, A<Never>> x;
+//                           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:32: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:32: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:37: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:37: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:30:35: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo1(F<A<dynamic>, A<Never>> x) {}
+//                                   ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:30:35: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo1(F<A<dynamic>, A<Never>> x) {}
+//                                   ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:31:11: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo2<X extends F<A<dynamic>, A<Never>>>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:31:11: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo2<X extends F<A<dynamic>, A<Never>>>() {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:32:34: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F<A<dynamic>, A<Never>> fooFoo4() => throw 42;
+//                                  ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:32:34: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F<A<dynamic>, A<Never>> fooFoo4() => throw 42;
+//                                  ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:33:45: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo5({required F<A<dynamic>, A<Never>> x}) {}
+//                                             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:33:45: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo5({required F<A<dynamic>, A<Never>> x}) {}
+//                                             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:34:37: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo7([F<A<dynamic>, A<Never>>? x]) {}
+//                                     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:34:37: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo7([F<A<dynamic>, A<Never>>? x]) {}
+//                                     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:38:5: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F x;
+//     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:38:5: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F x;
+//     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:10: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (F x in []) {}
+//          ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:10: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F x in []) {}
+//          ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:15: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (F x in []) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:15: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F x in []) {}
+//               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:40:13: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo1(F x) {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:40:13: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo1(F x) {}
+//             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:41:11: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo2<X extends F>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:41:11: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo2<X extends F>() {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:42:12: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F fooFoo4() => throw 42;
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:42:12: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F fooFoo4() => throw 42;
+//            ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:43:23: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo5({required F x}) {}
+//                       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:43:23: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo5({required F x}) {}
+//                       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:44:15: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo7([F? x]) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:44:15: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo7([F? x]) {}
+//               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:65:10: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   B<num> x;
+//          ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:66:15: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (B<num> x in []) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:72:7: Error: Type argument 'dynamic' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   new B<dynamic>();
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:66:20: Error: Inferred type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (B<num> x in []) {}
+//                    ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:67:18: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar1(B<num> x) {}
+//                  ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:68:11: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar2<X extends B<num>>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:69:17: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the return type.
+// Try changing type arguments so that they conform to the bounds.
+//   B<num> barBar4() => throw 42;
+//                 ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:70:28: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar5({required B<num> x}) {}
+//                            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:71:20: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar7([B<num>? x]) {}
+//                    ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef F<X extends self::A<X> = self::A<dynamic>, contravariant Y extends self::A<Y> = self::A<Never>> = (Y) → X;
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class Foo3a<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>> extends core::Object {
+  synthetic constructor •() → self::Foo3a<self::Foo3a::X>
+    : super core::Object::•()
+    ;
+}
+class Foo3b<X extends (self::A<Never>) → self::A<dynamic> = dynamic> extends core::Object {
+  synthetic constructor •() → self::Foo3b<self::Foo3b::X>
+    : super core::Object::•()
+    ;
+}
+class B<X extends core::int = core::int> extends core::Object {
+  synthetic constructor •() → self::B<self::B::X>
+    : super core::Object::•()
+    ;
+}
+class Bar3<X extends self::B<core::num> = self::B<core::num>> extends core::Object {
+  synthetic constructor •() → self::Bar3<self::Bar3::X>
+    : super core::Object::•()
+    ;
+}
+class Bar8 extends self::B<dynamic> {
+  synthetic constructor •() → self::Bar8
+    : super self::B::•()
+    ;
+}
+static method foo1a((self::A<Never>) → self::A<dynamic> x) → dynamic {}
+static method foo1b((self::A<Never>) → self::A<dynamic> x) → dynamic {}
+static method foo2a<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → dynamic {}
+static method foo2b<X extends (self::A<Never>) → self::A<dynamic> = dynamic>() → dynamic {}
+static method foo4a() → (self::A<Never>) → self::A<dynamic>
+  return throw 42;
+static method foo4b() → (self::A<Never>) → self::A<dynamic>
+  return throw 42;
+static method foo5a({required (self::A<Never>) → self::A<dynamic> x = #C1}) → dynamic {}
+static method foo5b({required (self::A<Never>) → self::A<dynamic> x = #C1}) → dynamic {}
+static method foo6a() → dynamic {
+  (self::A<Never>) → self::A<dynamic> x;
+  {
+    core::Iterator<(self::A<Never>) → self::A<dynamic>> :sync-for-iterator = core::_GrowableList::•<(self::A<Never>) → self::A<dynamic>>(0).{core::Iterable::iterator};
+    for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+      (self::A<Never>) → self::A<dynamic> x = :sync-for-iterator.{core::Iterator::current};
+      {}
+    }
+  }
+  function fooFoo1((self::A<Never>) → self::A<dynamic> x) → Null {}
+  function fooFoo2<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → Null {}
+  function fooFoo4() → (self::A<Never>) → self::A<dynamic>
+    return throw 42;
+  function fooFoo5({required (self::A<Never>) → self::A<dynamic> x = #C1}) → Null {}
+  function fooFoo7([(self::A<Never>) →? self::A<dynamic> x = #C1]) → Null {}
+}
+static method foo6b() → dynamic {
+  (self::A<Never>) → self::A<dynamic> x;
+  {
+    core::Iterator<(self::A<Never>) → self::A<dynamic>> :sync-for-iterator = core::_GrowableList::•<(self::A<Never>) → self::A<dynamic>>(0).{core::Iterable::iterator};
+    for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+      (self::A<Never>) → self::A<dynamic> x = :sync-for-iterator.{core::Iterator::current};
+      {}
+    }
+  }
+  function fooFoo1((self::A<Never>) → self::A<dynamic> x) → Null {}
+  function fooFoo2<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → Null {}
+  function fooFoo4() → (self::A<Never>) → self::A<dynamic>
+    return throw 42;
+  function fooFoo5({required (self::A<Never>) → self::A<dynamic> x = #C1}) → Null {}
+  function fooFoo7([(self::A<Never>) →? self::A<dynamic> x = #C1]) → Null {}
+}
+static method foo7a([(self::A<Never>) →? self::A<dynamic> x = #C1]) → dynamic {}
+static method foo7b([(self::A<Never>) →? self::A<dynamic> x = #C1]) → dynamic {}
+static method bar1(self::B<core::num> x) → dynamic {}
+static method bar2<X extends self::B<core::num> = self::B<core::num>>() → dynamic {}
+static method bar4() → self::B<core::num>
+  return throw 42;
+static method bar5({required self::B<core::num> x = #C1}) → dynamic {}
+static method bar6() → dynamic {
+  self::B<core::num> x;
+  {
+    core::Iterator<self::B<core::num>> :sync-for-iterator = core::_GrowableList::•<self::B<core::num>>(0).{core::Iterable::iterator};
+    for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+      self::B<core::num> x = :sync-for-iterator.{core::Iterator::current};
+      {}
+    }
+  }
+  function barBar1(self::B<core::num> x) → Null {}
+  function barBar2<X extends self::B<core::num> = self::B<core::num>>() → Null {}
+  function barBar4() → self::B<core::num>
+    return throw 42;
+  function barBar5({required self::B<core::num> x = #C1}) → Null {}
+  function barBar7([self::B<core::num>? x = #C1]) → Null {}
+  new self::B::•<dynamic>();
+  new self::A::•<self::B<dynamic>>();
+}
+static method bar7([self::B<core::num>? x = #C1]) → dynamic {}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.textual_outline.expect
new file mode 100644
index 0000000..7574af7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.textual_outline.expect
@@ -0,0 +1,36 @@
+class A<X> {}
+
+typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+foo1a(F<A<dynamic>, A<Never>> x) {}
+foo1b(F x) {}
+foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+foo2b<X extends F>() {}
+
+class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+
+class Foo3b<X extends F> {}
+
+F<A<dynamic>, A<Never>> foo4a() => throw 42;
+F foo4b() => throw 42;
+foo5a({required F<A<dynamic>, A<Never>> x}) {}
+foo5b({required F x}) {}
+foo6a() {}
+foo6b() {}
+foo7a([F<A<dynamic>, A<Never>>? x]) {}
+foo7b([F? x]) {}
+
+class B<X extends int> {}
+
+bar1(B<num> x) {}
+bar2<X extends B<num>>() {}
+
+class Bar3<X extends B<num>> {}
+
+B<num> bar4() => throw 42;
+bar5({required B<num> x}) {}
+bar6() {}
+bar7([B<num>? x]) {}
+
+class Bar8 extends B<dynamic> {}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..6dbf57e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.textual_outline_modelled.expect
@@ -0,0 +1,33 @@
+B<num> bar4() => throw 42;
+F<A<dynamic>, A<Never>> foo4a() => throw 42;
+F foo4b() => throw 42;
+bar1(B<num> x) {}
+bar2<X extends B<num>>() {}
+bar5({required B<num> x}) {}
+bar6() {}
+bar7([B<num>? x]) {}
+
+class A<X> {}
+
+class B<X extends int> {}
+
+class Bar3<X extends B<num>> {}
+
+class Bar8 extends B<dynamic> {}
+
+class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+
+class Foo3b<X extends F> {}
+
+foo1a(F<A<dynamic>, A<Never>> x) {}
+foo1b(F x) {}
+foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+foo2b<X extends F>() {}
+foo5a({required F<A<dynamic>, A<Never>> x}) {}
+foo5b({required F x}) {}
+foo6a() {}
+foo6b() {}
+foo7a([F<A<dynamic>, A<Never>>? x]) {}
+foo7b([F? x]) {}
+main() {}
+typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
diff --git a/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.weak.expect b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.weak.expect
new file mode 100644
index 0000000..98725b8
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.weak.expect
@@ -0,0 +1,618 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Error: Generic type 'F' can't be used without type arguments in a type variable bound.
+// Try providing type arguments to 'F' here.
+// foo2b<X extends F>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: Bound of this variable references variable 'X' from the same declaration.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:19:13: Error: Generic type 'F' can't be used without type arguments in a type variable bound.
+// Try providing type arguments to 'F' here.
+// class Foo3b<X extends F> {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: Bound of this variable references variable 'X' from the same declaration.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:11:31: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo1a(F<A<dynamic>, A<Never>> x) {}
+//                               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:11:31: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo1a(F<A<dynamic>, A<Never>> x) {}
+//                               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:12:9: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo1b(F x) {}
+//         ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:12:9: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo1b(F x) {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:14:7: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:14:7: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+//       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo2b<X extends F>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo2b<X extends F>() {}
+//       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:17:13: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:17:13: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+//             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:21:30: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// F<A<dynamic>, A<Never>> foo4a() => throw 42;
+//                              ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:21:30: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// F<A<dynamic>, A<Never>> foo4a() => throw 42;
+//                              ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:22:8: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// F foo4b() => throw 42;
+//        ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:22:8: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// F foo4b() => throw 42;
+//        ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:24:41: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo5a({required F<A<dynamic>, A<Never>> x}) {}
+//                                         ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:24:41: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo5a({required F<A<dynamic>, A<Never>> x}) {}
+//                                         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:25:19: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo5b({required F x}) {}
+//                   ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:25:19: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo5b({required F x}) {}
+//                   ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:47:33: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo7a([F<A<dynamic>, A<Never>>? x]) {}
+//                                 ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:47:33: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo7a([F<A<dynamic>, A<Never>>? x]) {}
+//                                 ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:48:11: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo7b([F? x]) {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:48:11: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo7b([F? x]) {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:54:13: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar1(B<num> x) {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:56:6: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2<X extends B<num>>() {}
+//      ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:58:12: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar3<X extends B<num>> {}
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:60:12: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the return type.
+// Try changing type arguments so that they conform to the bounds.
+// B<num> bar4() => throw 42;
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:62:23: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar5({required B<num> x}) {}
+//                       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:76:15: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar7([B<num>? x]) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:78:7: Error: Type argument 'dynamic' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the supertype 'B' of class 'Bar8'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar8 extends B<dynamic> {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:28:27: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F<A<dynamic>, A<Never>> x;
+//                           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:28:27: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F<A<dynamic>, A<Never>> x;
+//                           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:32: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:32: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:37: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:37: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:30:35: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo1(F<A<dynamic>, A<Never>> x) {}
+//                                   ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:30:35: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo1(F<A<dynamic>, A<Never>> x) {}
+//                                   ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:31:11: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo2<X extends F<A<dynamic>, A<Never>>>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:31:11: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo2<X extends F<A<dynamic>, A<Never>>>() {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:32:34: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F<A<dynamic>, A<Never>> fooFoo4() => throw 42;
+//                                  ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:32:34: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F<A<dynamic>, A<Never>> fooFoo4() => throw 42;
+//                                  ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:33:45: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo5({required F<A<dynamic>, A<Never>> x}) {}
+//                                             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:33:45: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo5({required F<A<dynamic>, A<Never>> x}) {}
+//                                             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:34:37: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo7([F<A<dynamic>, A<Never>>? x]) {}
+//                                     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:34:37: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo7([F<A<dynamic>, A<Never>>? x]) {}
+//                                     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:38:5: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F x;
+//     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:38:5: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F x;
+//     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:10: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (F x in []) {}
+//          ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:10: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F x in []) {}
+//          ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:15: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (F x in []) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:15: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F x in []) {}
+//               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:40:13: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo1(F x) {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:40:13: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo1(F x) {}
+//             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:41:11: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo2<X extends F>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:41:11: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo2<X extends F>() {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:42:12: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F fooFoo4() => throw 42;
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:42:12: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F fooFoo4() => throw 42;
+//            ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:43:23: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo5({required F x}) {}
+//                       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:43:23: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo5({required F x}) {}
+//                       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:44:15: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo7([F? x]) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:44:15: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo7([F? x]) {}
+//               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:65:10: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   B<num> x;
+//          ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:66:15: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (B<num> x in []) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:72:7: Error: Type argument 'dynamic' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   new B<dynamic>();
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:66:20: Error: Inferred type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (B<num> x in []) {}
+//                    ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:67:18: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar1(B<num> x) {}
+//                  ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:68:11: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar2<X extends B<num>>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:69:17: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the return type.
+// Try changing type arguments so that they conform to the bounds.
+//   B<num> barBar4() => throw 42;
+//                 ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:70:28: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar5({required B<num> x}) {}
+//                            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:71:20: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar7([B<num>? x]) {}
+//                    ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef F<X extends self::A<X> = self::A<dynamic>, contravariant Y extends self::A<Y> = self::A<Never>> = (Y) → X;
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class Foo3a<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>> extends core::Object {
+  synthetic constructor •() → self::Foo3a<self::Foo3a::X>
+    : super core::Object::•()
+    ;
+}
+class Foo3b<X extends (self::A<Never>) → self::A<dynamic> = dynamic> extends core::Object {
+  synthetic constructor •() → self::Foo3b<self::Foo3b::X>
+    : super core::Object::•()
+    ;
+}
+class B<X extends core::int = core::int> extends core::Object {
+  synthetic constructor •() → self::B<self::B::X>
+    : super core::Object::•()
+    ;
+}
+class Bar3<X extends self::B<core::num> = self::B<core::num>> extends core::Object {
+  synthetic constructor •() → self::Bar3<self::Bar3::X>
+    : super core::Object::•()
+    ;
+}
+class Bar8 extends self::B<dynamic> {
+  synthetic constructor •() → self::Bar8
+    : super self::B::•()
+    ;
+}
+static method foo1a((self::A<Never>) → self::A<dynamic> x) → dynamic {}
+static method foo1b((self::A<Never>) → self::A<dynamic> x) → dynamic {}
+static method foo2a<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → dynamic {}
+static method foo2b<X extends (self::A<Never>) → self::A<dynamic> = dynamic>() → dynamic {}
+static method foo4a() → (self::A<Never>) → self::A<dynamic>
+  return throw 42;
+static method foo4b() → (self::A<Never>) → self::A<dynamic>
+  return throw 42;
+static method foo5a({required (self::A<Never>) → self::A<dynamic> x = #C1}) → dynamic {}
+static method foo5b({required (self::A<Never>) → self::A<dynamic> x = #C1}) → dynamic {}
+static method foo6a() → dynamic {
+  (self::A<Never>) → self::A<dynamic> x;
+  for ((self::A<Never>) → self::A<dynamic> x in <(self::A<Never>) → self::A<dynamic>>[]) {
+  }
+  function fooFoo1((self::A<Never>) → self::A<dynamic> x) → Null {}
+  function fooFoo2<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → Null {}
+  function fooFoo4() → (self::A<Never>) → self::A<dynamic>
+    return throw 42;
+  function fooFoo5({required (self::A<Never>) → self::A<dynamic> x = #C1}) → Null {}
+  function fooFoo7([(self::A<Never>) →? self::A<dynamic> x = #C1]) → Null {}
+}
+static method foo6b() → dynamic {
+  (self::A<Never>) → self::A<dynamic> x;
+  for ((self::A<Never>) → self::A<dynamic> x in <(self::A<Never>) → self::A<dynamic>>[]) {
+  }
+  function fooFoo1((self::A<Never>) → self::A<dynamic> x) → Null {}
+  function fooFoo2<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → Null {}
+  function fooFoo4() → (self::A<Never>) → self::A<dynamic>
+    return throw 42;
+  function fooFoo5({required (self::A<Never>) → self::A<dynamic> x = #C1}) → Null {}
+  function fooFoo7([(self::A<Never>) →? self::A<dynamic> x = #C1]) → Null {}
+}
+static method foo7a([(self::A<Never>) →? self::A<dynamic> x = #C1]) → dynamic {}
+static method foo7b([(self::A<Never>) →? self::A<dynamic> x = #C1]) → dynamic {}
+static method bar1(self::B<core::num> x) → dynamic {}
+static method bar2<X extends self::B<core::num> = self::B<core::num>>() → dynamic {}
+static method bar4() → self::B<core::num>
+  return throw 42;
+static method bar5({required self::B<core::num> x = #C1}) → dynamic {}
+static method bar6() → dynamic {
+  self::B<core::num> x;
+  for (self::B<core::num> x in <self::B<core::num>>[]) {
+  }
+  function barBar1(self::B<core::num> x) → Null {}
+  function barBar2<X extends self::B<core::num> = self::B<core::num>>() → Null {}
+  function barBar4() → self::B<core::num>
+    return throw 42;
+  function barBar5({required self::B<core::num> x = #C1}) → Null {}
+  function barBar7([self::B<core::num>? x = #C1]) → Null {}
+  new self::B::•<dynamic>();
+  new self::A::•<self::B<dynamic>>();
+}
+static method bar7([self::B<core::num>? x = #C1]) → dynamic {}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.weak.transformed.expect
new file mode 100644
index 0000000..edb2e83
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/super_bounded_hint.dart.weak.transformed.expect
@@ -0,0 +1,633 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Error: Generic type 'F' can't be used without type arguments in a type variable bound.
+// Try providing type arguments to 'F' here.
+// foo2b<X extends F>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: Bound of this variable references variable 'X' from the same declaration.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:19:13: Error: Generic type 'F' can't be used without type arguments in a type variable bound.
+// Try providing type arguments to 'F' here.
+// class Foo3b<X extends F> {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: Bound of this variable references variable 'X' from the same declaration.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:11:31: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo1a(F<A<dynamic>, A<Never>> x) {}
+//                               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:11:31: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo1a(F<A<dynamic>, A<Never>> x) {}
+//                               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:12:9: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo1b(F x) {}
+//         ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:12:9: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo1b(F x) {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:14:7: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:14:7: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo2a<X extends F<A<dynamic>, A<Never>>>() {}
+//       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo2b<X extends F>() {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:15:7: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo2b<X extends F>() {}
+//       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:17:13: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:17:13: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// class Foo3a<X extends F<A<dynamic>, A<Never>>> {}
+//             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:21:30: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// F<A<dynamic>, A<Never>> foo4a() => throw 42;
+//                              ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:21:30: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// F<A<dynamic>, A<Never>> foo4a() => throw 42;
+//                              ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:22:8: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// F foo4b() => throw 42;
+//        ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:22:8: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// F foo4b() => throw 42;
+//        ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:24:41: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo5a({required F<A<dynamic>, A<Never>> x}) {}
+//                                         ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:24:41: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo5a({required F<A<dynamic>, A<Never>> x}) {}
+//                                         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:25:19: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo5b({required F x}) {}
+//                   ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:25:19: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo5b({required F x}) {}
+//                   ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:47:33: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// foo7a([F<A<dynamic>, A<Never>>? x]) {}
+//                                 ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:47:33: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo7a([F<A<dynamic>, A<Never>>? x]) {}
+//                                 ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:48:11: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// foo7b([F? x]) {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:48:11: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+// foo7b([F? x]) {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:54:13: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar1(B<num> x) {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:56:6: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2<X extends B<num>>() {}
+//      ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:58:12: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar3<X extends B<num>> {}
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:60:12: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the return type.
+// Try changing type arguments so that they conform to the bounds.
+// B<num> bar4() => throw 42;
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:62:23: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar5({required B<num> x}) {}
+//                       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:76:15: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// bar7([B<num>? x]) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:78:7: Error: Type argument 'dynamic' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the supertype 'B' of class 'Bar8'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar8 extends B<dynamic> {}
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:28:27: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F<A<dynamic>, A<Never>> x;
+//                           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:28:27: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F<A<dynamic>, A<Never>> x;
+//                           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:32: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:32: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:37: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:29:37: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F<A<dynamic>, A<Never>> x in []) {}
+//                                     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:30:35: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo1(F<A<dynamic>, A<Never>> x) {}
+//                                   ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:30:35: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo1(F<A<dynamic>, A<Never>> x) {}
+//                                   ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:31:11: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo2<X extends F<A<dynamic>, A<Never>>>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:31:11: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo2<X extends F<A<dynamic>, A<Never>>>() {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:32:34: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F<A<dynamic>, A<Never>> fooFoo4() => throw 42;
+//                                  ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:32:34: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F<A<dynamic>, A<Never>> fooFoo4() => throw 42;
+//                                  ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:33:45: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo5({required F<A<dynamic>, A<Never>> x}) {}
+//                                             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:33:45: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo5({required F<A<dynamic>, A<Never>> x}) {}
+//                                             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:34:37: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   fooFoo7([F<A<dynamic>, A<Never>>? x]) {}
+//                                     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:34:37: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo7([F<A<dynamic>, A<Never>>? x]) {}
+//                                     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:38:5: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F x;
+//     ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:38:5: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F x;
+//     ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:10: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (F x in []) {}
+//          ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:10: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F x in []) {}
+//          ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:15: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (F x in []) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:39:15: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   for (F x in []) {}
+//               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:40:13: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo1(F x) {}
+//             ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:40:13: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo1(F x) {}
+//             ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:41:11: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo2<X extends F>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:41:11: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo2<X extends F>() {}
+//           ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:42:12: Error: Type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F' in the return type.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   F fooFoo4() => throw 42;
+//            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:42:12: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   F fooFoo4() => throw 42;
+//            ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:43:23: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo5({required F x}) {}
+//                       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:43:23: Context: If you want 'F<A<dynamic>, A<Never>>' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo5({required F x}) {}
+//                       ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:44:15: Error: Inferred type argument 'A<dynamic>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'F'.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   fooFoo7([F? x]) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends A<X>, Y extends A<Y>> = X Function(Y);
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:44:15: Context: If you want 'F<A<dynamic>, A<Never>>?' to be a super-bounded type, note that the inverted type 'F<A<Never>, A<Object?>>?' must then satisfy its bounds, which it does not.
+//  - 'A' is from 'pkg/front_end/testcases/nnbd/super_bounded_hint.dart'.
+//  - 'Object' is from 'dart:core'.
+//   fooFoo7([F? x]) {}
+//               ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:65:10: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   B<num> x;
+//          ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:66:15: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   for (B<num> x in []) {}
+//               ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:72:7: Error: Type argument 'dynamic' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   new B<dynamic>();
+//       ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:66:20: Error: Inferred type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   for (B<num> x in []) {}
+//                    ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:67:18: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar1(B<num> x) {}
+//                  ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:68:11: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar2<X extends B<num>>() {}
+//           ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:69:17: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B' in the return type.
+// Try changing type arguments so that they conform to the bounds.
+//   B<num> barBar4() => throw 42;
+//                 ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:70:28: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar5({required B<num> x}) {}
+//                            ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:71:20: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+//   barBar7([B<num>? x]) {}
+//                    ^
+// pkg/front_end/testcases/nnbd/super_bounded_hint.dart:52:9: Context: This is the type variable whose bound isn't conformed to.
+// class B<X extends int> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef F<X extends self::A<X> = self::A<dynamic>, contravariant Y extends self::A<Y> = self::A<Never>> = (Y) → X;
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class Foo3a<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>> extends core::Object {
+  synthetic constructor •() → self::Foo3a<self::Foo3a::X>
+    : super core::Object::•()
+    ;
+}
+class Foo3b<X extends (self::A<Never>) → self::A<dynamic> = dynamic> extends core::Object {
+  synthetic constructor •() → self::Foo3b<self::Foo3b::X>
+    : super core::Object::•()
+    ;
+}
+class B<X extends core::int = core::int> extends core::Object {
+  synthetic constructor •() → self::B<self::B::X>
+    : super core::Object::•()
+    ;
+}
+class Bar3<X extends self::B<core::num> = self::B<core::num>> extends core::Object {
+  synthetic constructor •() → self::Bar3<self::Bar3::X>
+    : super core::Object::•()
+    ;
+}
+class Bar8 extends self::B<dynamic> {
+  synthetic constructor •() → self::Bar8
+    : super self::B::•()
+    ;
+}
+static method foo1a((self::A<Never>) → self::A<dynamic> x) → dynamic {}
+static method foo1b((self::A<Never>) → self::A<dynamic> x) → dynamic {}
+static method foo2a<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → dynamic {}
+static method foo2b<X extends (self::A<Never>) → self::A<dynamic> = dynamic>() → dynamic {}
+static method foo4a() → (self::A<Never>) → self::A<dynamic>
+  return throw 42;
+static method foo4b() → (self::A<Never>) → self::A<dynamic>
+  return throw 42;
+static method foo5a({required (self::A<Never>) → self::A<dynamic> x = #C1}) → dynamic {}
+static method foo5b({required (self::A<Never>) → self::A<dynamic> x = #C1}) → dynamic {}
+static method foo6a() → dynamic {
+  (self::A<Never>) → self::A<dynamic> x;
+  {
+    core::Iterator<(self::A<Never>) → self::A<dynamic>> :sync-for-iterator = core::_GrowableList::•<(self::A<Never>) → self::A<dynamic>>(0).{core::Iterable::iterator};
+    for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+      (self::A<Never>) → self::A<dynamic> x = :sync-for-iterator.{core::Iterator::current};
+      {}
+    }
+  }
+  function fooFoo1((self::A<Never>) → self::A<dynamic> x) → Null {}
+  function fooFoo2<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → Null {}
+  function fooFoo4() → (self::A<Never>) → self::A<dynamic>
+    return throw 42;
+  function fooFoo5({required (self::A<Never>) → self::A<dynamic> x = #C1}) → Null {}
+  function fooFoo7([(self::A<Never>) →? self::A<dynamic> x = #C1]) → Null {}
+}
+static method foo6b() → dynamic {
+  (self::A<Never>) → self::A<dynamic> x;
+  {
+    core::Iterator<(self::A<Never>) → self::A<dynamic>> :sync-for-iterator = core::_GrowableList::•<(self::A<Never>) → self::A<dynamic>>(0).{core::Iterable::iterator};
+    for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+      (self::A<Never>) → self::A<dynamic> x = :sync-for-iterator.{core::Iterator::current};
+      {}
+    }
+  }
+  function fooFoo1((self::A<Never>) → self::A<dynamic> x) → Null {}
+  function fooFoo2<X extends (self::A<Never>) → self::A<dynamic> = (self::A<Never>) → self::A<dynamic>>() → Null {}
+  function fooFoo4() → (self::A<Never>) → self::A<dynamic>
+    return throw 42;
+  function fooFoo5({required (self::A<Never>) → self::A<dynamic> x = #C1}) → Null {}
+  function fooFoo7([(self::A<Never>) →? self::A<dynamic> x = #C1]) → Null {}
+}
+static method foo7a([(self::A<Never>) →? self::A<dynamic> x = #C1]) → dynamic {}
+static method foo7b([(self::A<Never>) →? self::A<dynamic> x = #C1]) → dynamic {}
+static method bar1(self::B<core::num> x) → dynamic {}
+static method bar2<X extends self::B<core::num> = self::B<core::num>>() → dynamic {}
+static method bar4() → self::B<core::num>
+  return throw 42;
+static method bar5({required self::B<core::num> x = #C1}) → dynamic {}
+static method bar6() → dynamic {
+  self::B<core::num> x;
+  {
+    core::Iterator<self::B<core::num>> :sync-for-iterator = core::_GrowableList::•<self::B<core::num>>(0).{core::Iterable::iterator};
+    for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+      self::B<core::num> x = :sync-for-iterator.{core::Iterator::current};
+      {}
+    }
+  }
+  function barBar1(self::B<core::num> x) → Null {}
+  function barBar2<X extends self::B<core::num> = self::B<core::num>>() → Null {}
+  function barBar4() → self::B<core::num>
+    return throw 42;
+  function barBar5({required self::B<core::num> x = #C1}) → Null {}
+  function barBar7([self::B<core::num>? x = #C1]) → Null {}
+  new self::B::•<dynamic>();
+  new self::A::•<self::B<dynamic>>();
+}
+static method bar7([self::B<core::num>? x = #C1]) → dynamic {}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index c68cace..a9c7859 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -226,8 +226,20 @@
   /// The enclosing type of the issue, that is, the one with [typeParameter].
   final DartType enclosingType;
 
+  /// The type computed from [enclosingType] for the super-boundness check.
+  ///
+  /// This field can be null.  [invertedType] is supposed to enhance error
+  /// messages, providing the auxiliary type for super-boundness checks for the
+  /// user.  It is set to null if it's not helpful, for example, if
+  /// [enclosingType] is well-bounded or is strictly required to be
+  /// regular-bounded, so the super-boundness check is skipped.  It is set to
+  /// null also if the inversion didn't change the type at all, and it's not
+  /// helpful to show the same type to the user.
+  DartType invertedType;
+
   TypeArgumentIssue(
-      this.index, this.argument, this.typeParameter, this.enclosingType);
+      this.index, this.argument, this.typeParameter, this.enclosingType,
+      {this.invertedType});
 
   int get hashCode {
     int hash = 0x3fffffff & index;
@@ -293,30 +305,53 @@
     variables = type.typedefNode.typeParameters;
     arguments = type.typeArguments;
   } else if (type is FunctionType) {
-    List<TypeArgumentIssue> result = <TypeArgumentIssue>[];
+    List<TypeArgumentIssue> result = null;
+
     for (TypeParameter parameter in type.typeParameters) {
-      result.addAll(findTypeArgumentIssues(
-              library, parameter.bound, typeEnvironment, subtypeCheckMode,
-              allowSuperBounded: true) ??
-          const <TypeArgumentIssue>[]);
+      List<TypeArgumentIssue> parameterResult = findTypeArgumentIssues(
+          library, parameter.bound, typeEnvironment, subtypeCheckMode,
+          allowSuperBounded: true);
+      if (result == null) {
+        result = parameterResult;
+      } else if (parameterResult != null) {
+        result.addAll(parameterResult);
+      }
     }
+
     for (DartType formal in type.positionalParameters) {
-      result.addAll(findTypeArgumentIssues(
-              library, formal, typeEnvironment, subtypeCheckMode,
-              allowSuperBounded: true) ??
-          const <TypeArgumentIssue>[]);
+      List<TypeArgumentIssue> parameterResult = findTypeArgumentIssues(
+          library, formal, typeEnvironment, subtypeCheckMode,
+          allowSuperBounded: true);
+      if (result == null) {
+        result = parameterResult;
+      } else if (parameterResult != null) {
+        result.addAll(parameterResult);
+      }
     }
+
     for (NamedType named in type.namedParameters) {
-      result.addAll(findTypeArgumentIssues(
-              library, named.type, typeEnvironment, subtypeCheckMode,
-              allowSuperBounded: true) ??
-          const <TypeArgumentIssue>[]);
+      List<TypeArgumentIssue> parameterResult = findTypeArgumentIssues(
+          library, named.type, typeEnvironment, subtypeCheckMode,
+          allowSuperBounded: true);
+      if (result == null) {
+        result = parameterResult;
+      } else if (parameterResult != null) {
+        result.addAll(parameterResult);
+      }
     }
-    result.addAll(findTypeArgumentIssues(
-            library, type.returnType, typeEnvironment, subtypeCheckMode,
-            allowSuperBounded: true) ??
-        const <TypeArgumentIssue>[]);
-    return result.isEmpty ? null : result;
+
+    {
+      List<TypeArgumentIssue> returnTypeResult = findTypeArgumentIssues(
+          library, type.returnType, typeEnvironment, subtypeCheckMode,
+          allowSuperBounded: true);
+      if (result == null) {
+        result = returnTypeResult;
+      } else if (returnTypeResult != null) {
+        result.addAll(returnTypeResult);
+      }
+    }
+
+    return result;
   } else if (type is FutureOrType) {
     variables = typeEnvironment.coreTypes.futureClass.typeParameters;
     arguments = <DartType>[type.typeArgument];
@@ -326,8 +361,8 @@
 
   if (variables == null) return null;
 
-  List<TypeArgumentIssue> result;
-  List<TypeArgumentIssue> argumentsResult;
+  List<TypeArgumentIssue> result = null;
+  List<TypeArgumentIssue> argumentsResult = null;
 
   Map<TypeParameter, DartType> substitutionMap =
       new Map<TypeParameter, DartType>.fromIterables(variables, arguments);
@@ -343,11 +378,12 @@
         bound = legacyErasure(bound);
       }
       if (!typeEnvironment.isSubtypeOf(argument, bound, subtypeCheckMode)) {
-        // If the bound is InvalidType it's not checked, because an error was
-        // reported already at the time of the creation of InvalidType.
         result ??= <TypeArgumentIssue>[];
         result.add(new TypeArgumentIssue(i, argument, variables[i], type));
       }
+    } else {
+      // The bound is InvalidType so it's not checked, because an error was
+      // reported already at the time of the creation of InvalidType.
     }
 
     List<TypeArgumentIssue> issues = findTypeArgumentIssues(
@@ -371,18 +407,25 @@
   if (result == null) return null;
   if (!allowSuperBounded) return result;
 
-  List<TypeArgumentIssue> convertedResult = null;
-  type = convertSuperBoundedToRegularBounded(library, typeEnvironment, type);
-  List<DartType> argumentsToReport = arguments.toList();
-  if (type is InterfaceType) {
-    variables = type.classNode.typeParameters;
-    arguments = type.typeArguments;
-  } else if (type is TypedefType) {
-    variables = type.typedefNode.typeParameters;
-    arguments = type.typeArguments;
-  } else if (type is FutureOrType) {
+  bool isCorrectSuperBounded = true;
+  DartType invertedType =
+      convertSuperBoundedToRegularBounded(library, typeEnvironment, type);
+
+  // The auxiliary type is the same as [type].  At this point we know that
+  // [type] is not regular-bounded, which means that the inverted type is also
+  // not regular-bounded.  These two judgments together allow us to conclude
+  // that [type] is not well-bounded.
+  if (invertedType == null) return result;
+
+  if (invertedType is InterfaceType) {
+    variables = invertedType.classNode.typeParameters;
+    arguments = invertedType.typeArguments;
+  } else if (invertedType is TypedefType) {
+    variables = invertedType.typedefNode.typeParameters;
+    arguments = invertedType.typeArguments;
+  } else if (invertedType is FutureOrType) {
     variables = typeEnvironment.coreTypes.futureClass.typeParameters;
-    arguments = <DartType>[type.typeArgument];
+    arguments = <DartType>[invertedType.typeArgument];
   }
   substitutionMap =
       new Map<TypeParameter, DartType>.fromIterables(variables, arguments);
@@ -390,25 +433,31 @@
     DartType argument = arguments[i];
     if (isGenericFunctionTypeOrAlias(argument)) {
       // Generic function types aren't allowed as type arguments either.
-      convertedResult ??= <TypeArgumentIssue>[];
-      convertedResult.add(
-          new TypeArgumentIssue(i, argumentsToReport[i], variables[i], type));
+      isCorrectSuperBounded = false;
     } else if (!typeEnvironment.isSubtypeOf(argument,
         substitute(variables[i].bound, substitutionMap), subtypeCheckMode)) {
-      convertedResult ??= <TypeArgumentIssue>[];
-      convertedResult.add(
-          new TypeArgumentIssue(i, argumentsToReport[i], variables[i], type));
+      isCorrectSuperBounded = false;
     }
   }
   if (argumentsResult != null) {
-    convertedResult ??= <TypeArgumentIssue>[];
-    convertedResult.addAll(argumentsResult);
+    isCorrectSuperBounded = false;
   }
   if (typedefRhsResult != null) {
-    convertedResult ??= <TypeArgumentIssue>[];
-    convertedResult.addAll(typedefRhsResult);
+    isCorrectSuperBounded = false;
   }
-  return convertedResult == null || convertedResult.isEmpty ? null : result;
+
+  // The inverted type is regular-bounded, which means that [type] is
+  // well-bounded.
+  if (isCorrectSuperBounded) return null;
+
+  // The inverted type isn't regular-bounded, but it's different from [type].
+  // In this case we'll provide the programmer with the inverted type as a hint,
+  // in case they were going for a super-bounded type and will benefit from that
+  // information correcting the program.
+  for (TypeArgumentIssue issue in result) {
+    issue.invertedType = invertedType;
+  }
+  return result;
 }
 
 // Finds type arguments that don't follow the rules of well-boundness.
@@ -478,7 +527,7 @@
 
 /// Replaces all covariant occurrences of `dynamic`, `Object`, and `void` with
 /// [BottomType] and all contravariant occurrences of `Null` and [BottomType]
-/// with `Object`.
+/// with `Object`.  Returns null if the converted type is the same as [type].
 DartType convertSuperBoundedToRegularBounded(
     Library clientLibrary, TypeEnvironment typeEnvironment, DartType type,
     {int variance = Variance.covariant}) {
@@ -515,70 +564,162 @@
       type.classNode.typeParameters.isNotEmpty) {
     assert(type.classNode.typeParameters.length == type.typeArguments.length);
 
-    List<DartType> replacedTypeArguments = <DartType>[];
+    List<DartType> convertedTypeArguments = null;
     for (int i = 0; i < type.typeArguments.length; ++i) {
-      replacedTypeArguments.add(convertSuperBoundedToRegularBounded(
+      DartType convertedTypeArgument = convertSuperBoundedToRegularBounded(
           clientLibrary, typeEnvironment, type.typeArguments[i],
-          variance: variance));
+          variance: variance);
+      if (convertedTypeArgument != null) {
+        convertedTypeArguments ??= new List<DartType>.of(type.typeArguments);
+        convertedTypeArguments[i] = convertedTypeArgument;
+      }
     }
+    if (convertedTypeArguments == null) return null;
     return new InterfaceType(
-        type.classNode, type.nullability, replacedTypeArguments);
+        type.classNode, type.nullability, convertedTypeArguments);
   } else if (type is TypedefType &&
       type.typedefNode.typeParameters.isNotEmpty) {
     assert(type.typedefNode.typeParameters.length == type.typeArguments.length);
 
-    List<DartType> replacedTypeArguments = <DartType>[];
+    List<DartType> convertedTypeArguments = null;
     for (int i = 0; i < type.typeArguments.length; i++) {
       // The implementation of instantiate-to-bound in legacy mode ignored the
       // variance of type parameters of the typedef.  This behavior is preserved
       // here in passing the 'variance' parameter unchanged in for legacy
       // libraries.
-      replacedTypeArguments.add(convertSuperBoundedToRegularBounded(
+      DartType convertedTypeArgument = convertSuperBoundedToRegularBounded(
           clientLibrary, typeEnvironment, type.typeArguments[i],
           variance: clientLibrary.isNonNullableByDefault
               ? Variance.combine(
                   variance, type.typedefNode.typeParameters[i].variance)
-              : variance));
+              : variance);
+      if (convertedTypeArgument != null) {
+        convertedTypeArguments ??= new List<DartType>.of(type.typeArguments);
+        convertedTypeArguments[i] = convertedTypeArgument;
+      }
     }
+    if (convertedTypeArguments == null) return null;
     return new TypedefType(
-        type.typedefNode, type.nullability, replacedTypeArguments);
+        type.typedefNode, type.nullability, convertedTypeArguments);
   } else if (type is FunctionType) {
     if (clientLibrary.isNonNullableByDefault && type.typedefType != null) {
       return convertSuperBoundedToRegularBounded(
           clientLibrary, typeEnvironment, type.typedefType,
           variance: variance);
     }
-    DartType replacedReturnType = convertSuperBoundedToRegularBounded(
+
+    DartType convertedReturnType = convertSuperBoundedToRegularBounded(
         clientLibrary, typeEnvironment, type.returnType,
         variance: variance);
-    List<DartType> replacedPositionalParameters = <DartType>[];
+
+    List<DartType> convertedPositionalParameters = null;
     for (int i = 0; i < type.positionalParameters.length; i++) {
-      replacedPositionalParameters.add(convertSuperBoundedToRegularBounded(
-          clientLibrary, typeEnvironment, type.positionalParameters[i],
-          variance: Variance.combine(variance, Variance.contravariant)));
+      DartType convertedPositionalParameter =
+          convertSuperBoundedToRegularBounded(
+              clientLibrary, typeEnvironment, type.positionalParameters[i],
+              variance: Variance.combine(variance, Variance.contravariant));
+      if (convertedPositionalParameter != null) {
+        convertedPositionalParameters ??=
+            new List<DartType>.of(type.positionalParameters);
+        convertedPositionalParameters[i] = convertedPositionalParameter;
+      }
     }
-    List<NamedType> replacedNamedParameters = <NamedType>[];
+
+    List<NamedType> convertedNamedParameters = null;
     for (int i = 0; i < type.namedParameters.length; i++) {
-      replacedNamedParameters.add(new NamedType(
+      NamedType convertedNamedParameter = new NamedType(
           type.namedParameters[i].name,
           convertSuperBoundedToRegularBounded(
               clientLibrary, typeEnvironment, type.namedParameters[i].type,
-              variance: Variance.combine(variance, Variance.contravariant))));
+              variance: Variance.combine(variance, Variance.contravariant)),
+          isRequired: type.namedParameters[i].isRequired);
+      if (convertedNamedParameter != null) {
+        convertedNamedParameters ??=
+            new List<NamedType>.of(type.namedParameters);
+        convertedNamedParameters[i] = convertedNamedParameter;
+      }
     }
+
+    List<TypeParameter> convertedTypeParameters = null;
+    if (clientLibrary.isNonNullableByDefault &&
+        type.typeParameters.isNotEmpty) {
+      for (int i = 0; i < type.typeParameters.length; ++i) {
+        DartType convertedBound = convertSuperBoundedToRegularBounded(
+            clientLibrary, typeEnvironment, type.typeParameters[i].bound,
+            variance: Variance.combine(variance, Variance.invariant));
+        if (convertedBound != null) {
+          if (convertedTypeParameters == null) {
+            convertedTypeParameters = <TypeParameter>[];
+            for (TypeParameter parameter in type.typeParameters) {
+              convertedTypeParameters.add(new TypeParameter(parameter.name));
+            }
+          }
+          convertedTypeParameters[i].bound = convertedBound;
+        }
+      }
+
+      Map<TypeParameter, DartType> substitutionMap =
+          <TypeParameter, DartType>{};
+      for (int i = 0; i < type.typeParameters.length; ++i) {
+        substitutionMap[type.typeParameters[i]] =
+            new TypeParameterType.forAlphaRenaming(
+                type.typeParameters[i], convertedTypeParameters[i]);
+      }
+      for (TypeParameter parameter in convertedTypeParameters) {
+        parameter.bound = substitute(parameter.bound, substitutionMap);
+      }
+      List<DartType> defaultTypes = calculateBounds(convertedTypeParameters,
+          typeEnvironment.coreTypes.objectClass, clientLibrary);
+      for (int i = 0; i < convertedTypeParameters.length; ++i) {
+        convertedTypeParameters[i].defaultType = defaultTypes[i];
+      }
+
+      if (convertedReturnType != null) {
+        convertedReturnType = substitute(convertedReturnType, substitutionMap);
+      }
+      if (convertedPositionalParameters != null) {
+        for (int i = 0; i < convertedPositionalParameters.length; ++i) {
+          convertedPositionalParameters[i] =
+              substitute(convertedPositionalParameters[i], substitutionMap);
+        }
+      }
+      if (convertedNamedParameters != null) {
+        for (int i = 0; i < convertedNamedParameters.length; ++i) {
+          convertedNamedParameters[i] = new NamedType(
+              convertedNamedParameters[i].name,
+              substitute(convertedNamedParameters[i].type, substitutionMap),
+              isRequired: convertedNamedParameters[i].isRequired);
+        }
+      }
+    }
+
+    if (convertedReturnType == null &&
+        convertedPositionalParameters == null &&
+        convertedNamedParameters == null &&
+        convertedTypeParameters == null) {
+      return null;
+    }
+
+    convertedReturnType ??= type.returnType;
+    convertedPositionalParameters ??= type.positionalParameters;
+    convertedNamedParameters ??= type.namedParameters;
+    convertedTypeParameters ??= type.typeParameters;
+
     return new FunctionType(
-        replacedPositionalParameters, replacedReturnType, type.nullability,
-        namedParameters: replacedNamedParameters,
+        convertedPositionalParameters, convertedReturnType, type.nullability,
+        namedParameters: convertedNamedParameters,
         typeParameters: type.typeParameters,
         requiredParameterCount: type.requiredParameterCount,
         typedefType: type.typedefType);
   } else if (type is FutureOrType) {
-    return new FutureOrType(
-        convertSuperBoundedToRegularBounded(
-            clientLibrary, typeEnvironment, type.typeArgument,
-            variance: variance),
-        type.declaredNullability);
+    DartType convertedTypeArgument = convertSuperBoundedToRegularBounded(
+        clientLibrary, typeEnvironment, type.typeArgument,
+        variance: variance);
+    if (convertedTypeArgument == null) return null;
+    return new FutureOrType(convertedTypeArgument, type.declaredNullability);
   }
-  return type;
+
+  return null;
 }
 
 int computeVariance(TypeParameter typeParameter, DartType type,
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index 43e3c1c..0d1539d 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.dart
@@ -2,95 +2,93 @@
 // 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.
 
-/**
- * Support for asynchronous programming,
- * with classes such as Future and Stream.
- *
- * Understanding [Future]s and [Stream]s is a prerequisite for
- * writing just about any Dart program.
- *
- * To use this library in your code:
- *
- *     import 'dart:async';
- *
- * ## Future
- *
- * A Future object represents a computation whose return value
- * might not yet be available.
- * The Future returns the value of the computation
- * when it completes at some time in the future.
- * Futures are often used for potentially lengthy computations
- * such as I/O and interaction with users.
- *
- * Many methods in the Dart libraries return Futures when
- * performing tasks. For example, when binding an HttpServer
- * to a host and port, the `bind()` method returns a Future.
- *
- *      HttpServer.bind('127.0.0.1', 4444)
- *          .then((server) => print('${server.isBroadcast}'))
- *          .catchError(print);
- *
- * [Future.then] registers a callback function that runs
- * when the Future's operation, in this case the `bind()` method,
- * completes successfully.
- * The value returned by the operation
- * is passed into the callback function.
- * In this example, the `bind()` method returns the HttpServer
- * object. The callback function prints one of its properties.
- * [Future.catchError] registers a callback function that
- * runs if an error occurs within the Future.
- *
- * ## Stream
- *
- * A Stream provides an asynchronous sequence of data.
- * Examples of data sequences include individual events, like mouse clicks,
- * or sequential chunks of larger data, like multiple byte lists with the
- * contents of a file
- * such as mouse clicks, and a stream of byte lists read from a file.
- * The following example opens a file for reading.
- * [Stream.listen] registers a callback function that runs
- * each time more data is available.
- *
- *     Stream<List<int>> stream = new File('quotes.txt').openRead();
- *     stream.transform(utf8.decoder).listen(print);
- *
- * The stream emits a sequence of a list of bytes.
- * The program must interpret the bytes or handle the raw byte data.
- * Here, the code uses a UTF-8 decoder (provided in the `dart:convert` library)
- * to convert the sequence of bytes into a sequence
- * of Dart strings.
- *
- * Another common use of streams is for user-generated events
- * in a web app: The following code listens for mouse clicks on a button.
- *
- *     querySelector('#myButton').onClick.listen((_) => print('Click.'));
- *
- * ## Other resources
- *
- * * The [dart:async section of the library tour][asynchronous-programming]:
- *   A brief overview of asynchronous programming.
- *
- * * [Use Future-Based APIs][futures-tutorial]: A closer look at Futures and
- *   how to use them to write asynchronous Dart code.
- *
- * * [Futures and Error Handling][futures-error-handling]: Everything you
- *   wanted to know about handling errors and exceptions when working with
- *   Futures (but were afraid to ask).
- *
- * * [The Event Loop and Dart](https://dart.dev/articles/event-loop/):
- *   Learn how Dart handles the event queue and microtask queue, so you can
- *   write better asynchronous code with fewer surprises.
- *
- * * [test package: Asynchronous Tests][test-readme]: How to test asynchronous
- *   code.
- *
- * [asynchronous-programming]: https://dart.dev/guides/libraries/library-tour#dartasync---asynchronous-programming
- * [futures-tutorial]: https://dart.dev/codelabs/async-await
- * [futures-error-handling]: https://dart.dev/guides/libraries/futures-error-handling
- * [test-readme]: https://pub.dev/packages/test
- *
- * {@category Core}
- */
+/// Support for asynchronous programming,
+/// with classes such as Future and Stream.
+///
+/// Understanding [Future]s and [Stream]s is a prerequisite for
+/// writing just about any Dart program.
+///
+/// To use this library in your code:
+/// ```dart
+/// import 'dart:async';
+/// ```
+/// ## Future
+///
+/// A Future object represents a computation whose return value
+/// might not yet be available.
+/// The Future returns the value of the computation
+/// when it completes at some time in the future.
+/// Futures are often used for potentially lengthy computations
+/// such as I/O and interaction with users.
+///
+/// Many methods in the Dart libraries return Futures when
+/// performing tasks. For example, when binding an HttpServer
+/// to a host and port, the `bind()` method returns a Future.
+/// ```dart
+///  HttpServer.bind('127.0.0.1', 4444)
+///      .then((server) => print('${server.isBroadcast}'))
+///      .catchError(print);
+/// ```
+/// [Future.then] registers a callback function that runs
+/// when the Future's operation, in this case the `bind()` method,
+/// completes successfully.
+/// The value returned by the operation
+/// is passed into the callback function.
+/// In this example, the `bind()` method returns the HttpServer
+/// object. The callback function prints one of its properties.
+/// [Future.catchError] registers a callback function that
+/// runs if an error occurs within the Future.
+///
+/// ## Stream
+///
+/// A Stream provides an asynchronous sequence of data.
+/// Examples of data sequences include individual events, like mouse clicks,
+/// or sequential chunks of larger data, like multiple byte lists with the
+/// contents of a file
+/// such as mouse clicks, and a stream of byte lists read from a file.
+/// The following example opens a file for reading.
+/// [Stream.listen] registers a callback function that runs
+/// each time more data is available.
+/// ```dart
+/// Stream<List<int>> stream = File('quotes.txt').openRead();
+/// stream.transform(utf8.decoder).listen(print);
+/// ```
+/// The stream emits a sequence of a list of bytes.
+/// The program must interpret the bytes or handle the raw byte data.
+/// Here, the code uses a UTF-8 decoder (provided in the `dart:convert` library)
+/// to convert the sequence of bytes into a sequence
+/// of Dart strings.
+///
+/// Another common use of streams is for user-generated events
+/// in a web app: The following code listens for mouse clicks on a button.
+/// ```dart
+/// querySelector('#myButton').onClick.listen((_) => print('Click.'));
+/// ```
+/// ## Other resources
+///
+/// * The [dart:async section of the library tour][asynchronous-programming]:
+///   A brief overview of asynchronous programming.
+///
+/// * [Use Future-Based APIs][futures-tutorial]: A closer look at Futures and
+///   how to use them to write asynchronous Dart code.
+///
+/// * [Futures and Error Handling][futures-error-handling]: Everything you
+///   wanted to know about handling errors and exceptions when working with
+///   Futures (but were afraid to ask).
+///
+/// * [The Event Loop and Dart](https://dart.dev/articles/event-loop/):
+///   Learn how Dart handles the event queue and microtask queue, so you can
+///   write better asynchronous code with fewer surprises.
+///
+/// * [test package: Asynchronous Tests][test-readme]: How to test asynchronous
+///   code.
+///
+/// [asynchronous-programming]: https://dart.dev/guides/libraries/library-tour#dartasync---asynchronous-programming
+/// [futures-tutorial]: https://dart.dev/codelabs/async-await
+/// [futures-error-handling]: https://dart.dev/guides/libraries/futures-error-handling
+/// [test-readme]: https://pub.dev/packages/test
+///
+/// {@category Core}
 library dart.async;
 
 import "dart:collection" show HashMap;
diff --git a/sdk/lib/async/async_error.dart b/sdk/lib/async/async_error.dart
index a7172bd..2340a41 100644
--- a/sdk/lib/async/async_error.dart
+++ b/sdk/lib/async/async_error.dart
@@ -4,6 +4,35 @@
 
 part of dart.async;
 
+/// An error and a stack trace.
+///
+/// Used when an error and stack trace need to be handled as a single
+/// value, for example when returned by [Zone.errorCallback].
+class AsyncError implements Error {
+  final Object error;
+  final StackTrace stackTrace;
+
+  AsyncError(Object error, StackTrace? stackTrace)
+      : error = checkNotNullable(error, "error"),
+        stackTrace = stackTrace ?? defaultStackTrace(error);
+
+  /// A default stack trace for an error.
+  ///
+  /// If [error] is an [Error] and it has an [Error.stackTrace],
+  /// that stack trace is returned.
+  /// If not, the [StackTrace.empty] default stack trace is returned.
+  static StackTrace defaultStackTrace(Object error) {
+    if (error is Error) {
+      var stackTrace = error.stackTrace;
+      if (stackTrace != null) return stackTrace;
+    }
+    return StackTrace.empty;
+  }
+
+  String toString() => '$error';
+}
+
+// Helper function used by stream method implementations.
 _invokeErrorHandler(
     Function errorHandler, Object error, StackTrace stackTrace) {
   var handler = errorHandler; // Rename to avoid promotion.
diff --git a/sdk/lib/async/broadcast_stream_controller.dart b/sdk/lib/async/broadcast_stream_controller.dart
index 4db2a34..c2db270 100644
--- a/sdk/lib/async/broadcast_stream_controller.dart
+++ b/sdk/lib/async/broadcast_stream_controller.dart
@@ -81,19 +81,17 @@
   // Extra state used during an [addStream] call.
   _AddStreamState<T>? _addStreamState;
 
-  /**
-   * Future returned by [close] and [done].
-   *
-   * The future is completed whenever the done event has been sent to all
-   * relevant listeners.
-   * The relevant listeners are the ones that were listening when [close] was
-   * called. When all of these have been canceled (sending the done event makes
-   * them cancel, but they can also be canceled before sending the event),
-   * this future completes.
-   *
-   * Any attempt to listen after calling [close] will throw, so there won't
-   * be any further listeners.
-   */
+  /// Future returned by [close] and [done].
+  ///
+  /// The future is completed whenever the done event has been sent to all
+  /// relevant listeners.
+  /// The relevant listeners are the ones that were listening when [close] was
+  /// called. When all of these have been canceled (sending the done event makes
+  /// them cancel, but they can also be canceled before sending the event),
+  /// this future completes.
+  ///
+  /// Any attempt to listen after calling [close] will throw, so there won't
+  /// be any further listeners.
   _Future<void>? _doneFuture;
 
   _BroadcastStreamController(this.onListen, this.onCancel)
@@ -127,28 +125,24 @@
 
   bool get isClosed => (_state & _STATE_CLOSED) != 0;
 
-  /**
-   * A broadcast controller is never paused.
-   *
-   * Each receiving stream may be paused individually, and they handle their
-   * own buffering.
-   */
+  /// A broadcast controller is never paused.
+  ///
+  /// Each receiving stream may be paused individually, and they handle their
+  /// own buffering.
   bool get isPaused => false;
 
-  /** Whether there are currently one or more subscribers. */
+  /// Whether there are currently one or more subscribers.
   bool get hasListener => !_isEmpty;
 
-  /**
-   * Test whether the stream has exactly one listener.
-   *
-   * Assumes that the stream has a listener (not [_isEmpty]).
-   */
+  /// Test whether the stream has exactly one listener.
+  ///
+  /// Assumes that the stream has a listener (not [_isEmpty]).
   bool get _hasOneListener {
     assert(!_isEmpty);
     return identical(_firstSubscription, _lastSubscription);
   }
 
-  /** Whether an event is being fired (sent to some, but not all, listeners). */
+  /// Whether an event is being fired (sent to some, but not all, listeners).
   bool get _isFiring => (_state & _STATE_FIRING) != 0;
 
   bool get _isAddingStream => (_state & _STATE_ADDSTREAM) != 0;
@@ -161,7 +155,7 @@
 
   bool get _isEmpty => _firstSubscription == null;
 
-  /** Adds subscription to linked list of active listeners. */
+  /// Adds subscription to linked list of active listeners.
   void _addListener(_BroadcastSubscription<T> subscription) {
     assert(identical(subscription._next, subscription));
     subscription._eventState = (_state & _STATE_EVENT_ID);
@@ -448,17 +442,15 @@
   }
 }
 
-/**
- * Stream controller that is used by [Stream.asBroadcastStream].
- *
- * This stream controller allows incoming events while it is firing
- * other events. This is handled by delaying the events until the
- * current event is done firing, and then fire the pending events.
- *
- * This class extends [_SyncBroadcastStreamController]. Events of
- * an "asBroadcastStream" stream are always initiated by events
- * on another stream, and it is fine to forward them synchronously.
- */
+/// Stream controller that is used by [Stream.asBroadcastStream].
+///
+/// This stream controller allows incoming events while it is firing
+/// other events. This is handled by delaying the events until the
+/// current event is done firing, and then fire the pending events.
+///
+/// This class extends [_SyncBroadcastStreamController]. Events of
+/// an "asBroadcastStream" stream are always initiated by events
+/// on another stream, and it is fine to forward them synchronously.
 class _AsBroadcastStreamController<T> extends _SyncBroadcastStreamController<T>
     implements _EventDispatch<T> {
   _StreamImplEvents<T>? _pending;
diff --git a/sdk/lib/async/deferred_load.dart b/sdk/lib/async/deferred_load.dart
index 419db58..81d9f80 100644
--- a/sdk/lib/async/deferred_load.dart
+++ b/sdk/lib/async/deferred_load.dart
@@ -4,12 +4,12 @@
 
 part of dart.async;
 
-/**
- * Indicates that loading of [libraryName] is deferred.
- *
- * This class is obsolete. Instead use the syntax:
- * import "library.dart" deferred as prefix;
- */
+/// Indicates that loading of [libraryName] is deferred.
+///
+/// This class is obsolete. Instead use the syntax:
+/// ```dart
+/// import "library.dart" deferred as prefix;
+/// ```
 @Deprecated("Dart sdk v. 1.8")
 class DeferredLibrary {
   final String libraryName;
@@ -17,18 +17,14 @@
 
   const DeferredLibrary(this.libraryName, {this.uri});
 
-  /**
-   * Ensure that [libraryName] has been loaded.
-   *
-   * If the library fails to load, the Future will complete with a
-   * DeferredLoadException.
-   */
+  /// Ensure that [libraryName] has been loaded.
+  ///
+  /// If the library fails to load, the [Future] will complete with a
+  /// [DeferredLoadException].
   external Future<Null> load();
 }
 
-/**
- * Thrown when a deferred library fails to load.
- */
+/// Thrown when a deferred library fails to load.
 class DeferredLoadException implements Exception {
   DeferredLoadException(String message) : _s = message;
   String toString() => "DeferredLoadException: '$_s'";
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 0473bc3..317c1fe 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -43,108 +43,106 @@
   }
 }
 
-/**
- * An object representing a delayed computation.
- *
- * A [Future] is used to represent a potential value, or error,
- * that will be available at some time in the future.
- * Receivers of a [Future] can register callbacks
- * that handle the value or error once it is available.
- * For example:
- *
- *     Future<int> future = getFuture();
- *     future.then((value) => handleValue(value))
- *           .catchError((error) => handleError(error));
- *
- * A [Future] can be completed in two ways:
- * with a value ("the future succeeds")
- * or with an error ("the future fails").
- * Users can install callbacks for each case.
- *
- * In some cases we say that a future is completed with another future.
- * This is a short way of stating that the future is completed in the same way,
- * with the same value or error,
- * as the other future once that completes.
- * Whenever a function in the core library may complete a future
- * (for example [Completer.complete] or [new Future.value]),
- * then it also accepts another future and does this work for the developer.
- *
- * The result of registering a pair of callbacks is a new Future (the
- * "successor") which in turn is completed with the result of invoking the
- * corresponding callback.
- * The successor is completed with an error if the invoked callback throws.
- * For example:
- * ```
- * Future<int> successor = future.then((int value) {
- *     // Invoked when the future is completed with a value.
- *     return 42;  // The successor is completed with the value 42.
- *   },
- *   onError: (e) {
- *     // Invoked when the future is completed with an error.
- *     if (canHandle(e)) {
- *       return 499;  // The successor is completed with the value 499.
- *     } else {
- *       throw e;  // The successor is completed with the error e.
- *     }
- *   });
- * ```
- *
- * If a future does not have a successor when it completes with an error,
- * it forwards the error message to the global error-handler.
- * This behavior makes sure that no error is silently dropped.
- * However, it also means that error handlers should be installed early,
- * so that they are present as soon as a future is completed with an error.
- * The following example demonstrates this potential bug:
- * ```
- * var future = getFuture();
- * new Timer(new Duration(milliseconds: 5), () {
- *   // The error-handler is not attached until 5 ms after the future has
- *   // been received. If the future fails before that, the error is
- *   // forwarded to the global error-handler, even though there is code
- *   // (just below) to eventually handle the error.
- *   future.then((value) { useValue(value); },
- *               onError: (e) { handleError(e); });
- * });
- * ```
- *
- * When registering callbacks, it's often more readable to register the two
- * callbacks separately, by first using [then] with one argument
- * (the value handler) and using a second [catchError] for handling errors.
- * Each of these will forward the result that they don't handle
- * to their successors, and together they handle both value and error result.
- * It also has the additional benefit of the [catchError] handling errors in the
- * [then] value callback too.
- * Using sequential handlers instead of parallel ones often leads to code that
- * is easier to reason about.
- * It also makes asynchronous code very similar to synchronous code:
- * ```
- * // Synchronous code.
- * try {
- *   int value = foo();
- *   return bar(value);
- * } catch (e) {
- *   return 499;
- * }
- * ```
- *
- * Equivalent asynchronous code, based on futures:
- * ```
- * Future<int> future = new Future(foo);  // Result of foo() as a future.
- * future.then((int value) => bar(value))
- *       .catchError((e) => 499);
- * ```
- *
- * Similar to the synchronous code, the error handler (registered with
- * [catchError]) is handling any errors thrown by either `foo` or `bar`.
- * If the error-handler had been registered as the `onError` parameter of
- * the `then` call, it would not catch errors from the `bar` call.
- *
- * Futures can have more than one callback-pair registered. Each successor is
- * treated independently and is handled as if it was the only successor.
- *
- * A future may also fail to ever complete. In that case, no callbacks are
- * called.
- */
+/// An object representing a delayed computation.
+///
+/// A [Future] is used to represent a potential value, or error,
+/// that will be available at some time in the future.
+/// Receivers of a [Future] can register callbacks
+/// that handle the value or error once it is available.
+/// For example:
+/// ```dart
+/// Future<int> future = getFuture();
+/// future.then((value) => handleValue(value))
+///       .catchError((error) => handleError(error));
+/// ```
+/// A [Future] can be completed in two ways:
+/// with a value ("the future succeeds")
+/// or with an error ("the future fails").
+/// Users can install callbacks for each case.
+///
+/// In some cases we say that a future is completed with another future.
+/// This is a short way of stating that the future is completed in the same way,
+/// with the same value or error,
+/// as the other future once that completes.
+/// Whenever a function in the core library may complete a future
+/// (for example [Completer.complete] or [Future.value]),
+/// then it also accepts another future and does this work for the developer.
+///
+/// The result of registering a pair of callbacks is a Future (the
+/// "successor") which in turn is completed with the result of invoking the
+/// corresponding callback.
+/// The successor is completed with an error if the invoked callback throws.
+/// For example:
+/// ```
+/// Future<int> successor = future.then((int value) {
+///     // Invoked when the future is completed with a value.
+///     return 42;  // The successor is completed with the value 42.
+///   },
+///   onError: (e) {
+///     // Invoked when the future is completed with an error.
+///     if (canHandle(e)) {
+///       return 499;  // The successor is completed with the value 499.
+///     } else {
+///       throw e;  // The successor is completed with the error e.
+///     }
+///   });
+/// ```
+///
+/// If a future does not have a successor when it completes with an error,
+/// it forwards the error message to an uncaught-error handler.
+/// This behavior makes sure that no error is silently dropped.
+/// However, it also means that error handlers should be installed early,
+/// so that they are present as soon as a future is completed with an error.
+/// The following example demonstrates this potential bug:
+/// ```
+/// var future = getFuture();
+/// Timer(const Duration(milliseconds: 5), () {
+///   // The error-handler is not attached until 5 ms after the future has
+///   // been received. If the future fails before that, the error is
+///   // forwarded to the global error-handler, even though there is code
+///   // (just below) to eventually handle the error.
+///   future.then((value) { useValue(value); },
+///               onError: (e) { handleError(e); });
+/// });
+/// ```
+///
+/// When registering callbacks, it's often more readable to register the two
+/// callbacks separately, by first using [then] with one argument
+/// (the value handler) and using a second [catchError] for handling errors.
+/// Each of these will forward the result that they don't handle
+/// to their successors, and together they handle both value and error result.
+/// It also has the additional benefit of the [catchError] handling errors in the
+/// [then] value callback too.
+/// Using sequential handlers instead of parallel ones often leads to code that
+/// is easier to reason about.
+/// It also makes asynchronous code very similar to synchronous code:
+/// ```
+/// // Synchronous code.
+/// try {
+///   int value = foo();
+///   return bar(value);
+/// } catch (e) {
+///   return 499;
+/// }
+/// ```
+///
+/// Equivalent asynchronous code, based on futures:
+/// ```
+/// Future<int> future = Future(foo);  // Result of foo() as a future.
+/// future.then((int value) => bar(value))
+///       .catchError((e) => 499);
+/// ```
+///
+/// Similar to the synchronous code, the error handler (registered with
+/// [catchError]) is handling any errors thrown by either `foo` or `bar`.
+/// If the error-handler had been registered as the `onError` parameter of
+/// the `then` call, it would not catch errors from the `bar` call.
+///
+/// Futures can have more than one callback-pair registered. Each successor is
+/// treated independently and is handled as if it was the only successor.
+///
+/// A future may also fail to ever complete. In that case, no callbacks are
+/// called.
 abstract class Future<T> {
   /// A `Future<Null>` completed with `null`.
   ///
@@ -157,20 +155,18 @@
   static final _Future<bool> _falseFuture =
       new _Future<bool>.zoneValue(false, _rootZone);
 
-  /**
-   * Creates a future containing the result of calling [computation]
-   * asynchronously with [Timer.run].
-   *
-   * If the result of executing [computation] throws, the returned future is
-   * completed with the error.
-   *
-   * If the returned value is itself a [Future], completion of
-   * the created future will wait until the returned future completes,
-   * and will then complete with the same result.
-   *
-   * If a non-future value is returned, the returned future is completed
-   * with that value.
-   */
+  /// Creates a future containing the result of calling [computation]
+  /// asynchronously with [Timer.run].
+  ///
+  /// If the result of executing [computation] throws, the returned future is
+  /// completed with the error.
+  ///
+  /// If the returned value is itself a [Future], completion of
+  /// the created future will wait until the returned future completes,
+  /// and will then complete with the same result.
+  ///
+  /// If a non-future value is returned, the returned future is completed
+  /// with that value.
   factory Future(FutureOr<T> computation()) {
     _Future<T> result = new _Future<T>();
     Timer.run(() {
@@ -183,20 +179,18 @@
     return result;
   }
 
-  /**
-   * Creates a future containing the result of calling [computation]
-   * asynchronously with [scheduleMicrotask].
-   *
-   * If executing [computation] throws,
-   * the returned future is completed with the thrown error.
-   *
-   * If calling [computation] returns a [Future], completion of
-   * the created future will wait until the returned future completes,
-   * and will then complete with the same result.
-   *
-   * If calling [computation] returns a non-future value,
-   * the returned future is completed with that value.
-   */
+  /// Creates a future containing the result of calling [computation]
+  /// asynchronously with [scheduleMicrotask].
+  ///
+  /// If executing [computation] throws,
+  /// the returned future is completed with the thrown error.
+  ///
+  /// If calling [computation] returns a [Future], completion of
+  /// the created future will wait until the returned future completes,
+  /// and will then complete with the same result.
+  ///
+  /// If calling [computation] returns a non-future value,
+  /// the returned future is completed with that value.
   factory Future.microtask(FutureOr<T> computation()) {
     _Future<T> result = new _Future<T>();
     scheduleMicrotask(() {
@@ -209,18 +203,16 @@
     return result;
   }
 
-  /**
-   * Returns a future containing the result of immediately calling
-   * [computation].
-   *
-   * If calling [computation] throws, the returned future is completed with the
-   * error.
-   *
-   * If calling [computation] returns a `Future<T>`, that future is returned.
-   *
-   * If calling [computation] returns a non-future value,
-   * a future is returned which has been completed with that value.
-   */
+  /// Returns a future containing the result of immediately calling
+  /// [computation].
+  ///
+  /// If calling [computation] throws, the returned future is completed with the
+  /// error.
+  ///
+  /// If calling [computation] returns a `Future<T>`, that future is returned.
+  ///
+  /// If calling [computation] returns a non-future value,
+  /// a future is returned which has been completed with that value.
   factory Future.sync(FutureOr<T> computation()) {
     try {
       var result = computation();
@@ -242,40 +234,36 @@
     }
   }
 
-  /**
-   * Creates a future completed with [value].
-   *
-   * If [value] is a future, the created future waits for the
-   * [value] future to complete, and then completes with the same result.
-   * Since a [value] future can complete with an error, so can the future
-   * created by [Future.value], even if the name suggests otherwise.
-   *
-   * If [value] is not a [Future], the created future is completed
-   * with the [value] value,
-   * equivalently to `new Future<T>.sync(() => value)`.
-   *
-   * If [value] is omitted or `null`, it is converted to `FutureOr<T>` by
-   * `value as FutureOr<T>`. If `T` is not nullable, then the [value] is
-   * required, otherwise the construction throws.
-   *
-   * Use [Completer] to create a future and complete it later.
-   */
+  /// Creates a future completed with [value].
+  ///
+  /// If [value] is a future, the created future waits for the
+  /// [value] future to complete, and then completes with the same result.
+  /// Since a [value] future can complete with an error, so can the future
+  /// created by [Future.value], even if the name suggests otherwise.
+  ///
+  /// If [value] is not a [Future], the created future is completed
+  /// with the [value] value,
+  /// equivalently to `new Future<T>.sync(() => value)`.
+  ///
+  /// If [value] is omitted or `null`, it is converted to `FutureOr<T>` by
+  /// `value as FutureOr<T>`. If `T` is not nullable, then a non-`null` [value]
+  /// must be provided, otherwise the construction throws.
+  ///
+  /// Use [Completer] to create a future now and complete it later.
   @pragma("vm:entry-point")
   @pragma("vm:prefer-inline")
   factory Future.value([FutureOr<T>? value]) {
     return new _Future<T>.immediate(value == null ? value as T : value);
   }
 
-  /**
-   * Creates a future that completes with an error.
-   *
-   * The created future will be completed with an error in a future microtask.
-   * This allows enough time for someone to add an error handler on the future.
-   * If an error handler isn't added before the future completes, the error
-   * will be considered unhandled.
-   *
-   * Use [Completer] to create a future and complete it later.
-   */
+  /// Creates a future that completes with an error.
+  ///
+  /// The created future will be completed with an error in a future microtask.
+  /// This allows enough time for someone to add an error handler on the future.
+  /// If an error handler isn't added before the future completes, the error
+  /// will be considered unhandled.
+  ///
+  /// Use [Completer] to create a future and complete it later.
   factory Future.error(Object error, [StackTrace? stackTrace]) {
     // TODO(40614): Remove once non-nullability is sound.
     checkNotNullable(error, "error");
@@ -290,31 +278,29 @@
     return new _Future<T>.immediateError(error, stackTrace);
   }
 
-  /**
-   * Creates a future that runs its computation after a delay.
-   *
-   * The [computation] will be executed after the given [duration] has passed,
-   * and the future is completed with the result of the computation.
-   *
-   * If [computation] returns a future,
-   * the future returned by this constructor will complete with the value or
-   * error of that future.
-   *
-   * If the duration is 0 or less,
-   * it completes no sooner than in the next event-loop iteration,
-   * after all microtasks have run.
-   *
-   * If [computation] is omitted,
-   * it will be treated as if [computation] was `() => null`,
-   * and the future will eventually complete with the `null` value.
-   * In that case, [T] must be nullable.
-   *
-   * If calling [computation] throws, the created future will complete with the
-   * error.
-   *
-   * See also [Completer] for a way to create and complete a future at a
-   * later time that isn't necessarily after a known fixed duration.
-   */
+  /// Creates a future that runs its computation after a delay.
+  ///
+  /// The [computation] will be executed after the given [duration] has passed,
+  /// and the future is completed with the result of the computation.
+  ///
+  /// If [computation] returns a future,
+  /// the future returned by this constructor will complete with the value or
+  /// error of that future.
+  ///
+  /// If the duration is 0 or less,
+  /// it completes no sooner than in the next event-loop iteration,
+  /// after all microtasks have run.
+  ///
+  /// If [computation] is omitted,
+  /// it will be treated as if [computation] was `() => null`,
+  /// and the future will eventually complete with the `null` value.
+  /// In that case, [T] must be nullable.
+  ///
+  /// If calling [computation] throws, the created future will complete with the
+  /// error.
+  ///
+  /// See also [Completer] for a way to create and complete a future at a
+  /// later time that isn't necessarily after a known fixed duration.
   factory Future.delayed(Duration duration, [FutureOr<T> computation()?]) {
     if (computation == null && !typeAcceptsNull<T>()) {
       throw ArgumentError.value(
@@ -335,35 +321,33 @@
     return result;
   }
 
-  /**
-   * Waits for multiple futures to complete and collects their results.
-   *
-   * Returns a future which will complete once all the provided futures
-   * have completed, either with their results, or with an error if any
-   * of the provided futures fail.
-   *
-   * The value of the returned future will be a list of all the values that
-   * were produced in the order that the futures are provided by iterating
-   * [futures].
-   *
-   * If any future completes with an error,
-   * then the returned future completes with that error.
-   * If further futures also complete with errors, those errors are discarded.
-   *
-   * If `eagerError` is true, the returned future completes with an error
-   * immediately on the first error from one of the futures. Otherwise all
-   * futures must complete before the returned future is completed (still with
-   * the first error; the remaining errors are silently dropped).
-   *
-   * In the case of an error, [cleanUp] (if provided), is invoked on any
-   * non-null result of successful futures.
-   * This makes it possible to `cleanUp` resources that would otherwise be
-   * lost (since the returned future does not provide access to these values).
-   * The [cleanUp] function is unused if there is no error.
-   *
-   * The call to [cleanUp] should not throw. If it does, the error will be an
-   * uncaught asynchronous error.
-   */
+  /// Waits for multiple futures to complete and collects their results.
+  ///
+  /// Returns a future which will complete once all the provided futures
+  /// have completed, either with their results, or with an error if any
+  /// of the provided futures fail.
+  ///
+  /// The value of the returned future will be a list of all the values that
+  /// were produced in the order that the futures are provided by iterating
+  /// [futures].
+  ///
+  /// If any future completes with an error,
+  /// then the returned future completes with that error.
+  /// If further futures also complete with errors, those errors are discarded.
+  ///
+  /// If `eagerError` is true, the returned future completes with an error
+  /// immediately on the first error from one of the futures. Otherwise all
+  /// futures must complete before the returned future is completed (still with
+  /// the first error; the remaining errors are silently dropped).
+  ///
+  /// In the case of an error, [cleanUp] (if provided), is invoked on any
+  /// non-null result of successful futures.
+  /// This makes it possible to `cleanUp` resources that would otherwise be
+  /// lost (since the returned future does not provide access to these values).
+  /// The [cleanUp] function is unused if there is no error.
+  ///
+  /// The call to [cleanUp] should not throw. If it does, the error will be an
+  /// uncaught asynchronous error.
   @pragma("vm:recognized", "other")
   static Future<List<T>> wait<T>(Iterable<Future<T>> futures,
       {bool eagerError = false, void cleanUp(T successValue)?}) {
@@ -463,17 +447,15 @@
     return _future;
   }
 
-  /**
-   * Returns the result of the first future in [futures] to complete.
-   *
-   * The returned future is completed with the result of the first
-   * future in [futures] to report that it is complete,
-   * whether it's with a value or an error.
-   * The results of all the other futures are discarded.
-   *
-   * If [futures] is empty, or if none of its futures complete,
-   * the returned future never completes.
-   */
+  /// Returns the result of the first future in [futures] to complete.
+  ///
+  /// The returned future is completed with the result of the first
+  /// future in [futures] to report that it is complete,
+  /// whether it's with a value or an error.
+  /// The results of all the other futures are discarded.
+  ///
+  /// If [futures] is empty, or if none of its futures complete,
+  /// the returned future never completes.
   static Future<T> any<T>(Iterable<Future<T>> futures) {
     var completer = new Completer<T>.sync();
     void onValue(T value) {
@@ -490,24 +472,22 @@
     return completer.future;
   }
 
-  /**
-   * Performs an action for each element of the iterable, in turn.
-   *
-   * The [action] may be either synchronous or asynchronous.
-   *
-   * Calls [action] with each element in [elements] in order.
-   * If the call to [action] returns a `Future<T>`, the iteration waits
-   * until the future is completed before continuing with the next element.
-   *
-   * Returns a [Future] that completes with `null` when all elements have been
-   * processed.
-   *
-   * Non-[Future] return values, and completion-values of returned [Future]s,
-   * are discarded.
-   *
-   * Any error from [action], synchronous or asynchronous,
-   * will stop the iteration and be reported in the returned [Future].
-   */
+  /// Performs an action for each element of the iterable, in turn.
+  ///
+  /// The [action] may be either synchronous or asynchronous.
+  ///
+  /// Calls [action] with each element in [elements] in order.
+  /// If the call to [action] returns a `Future<T>`, the iteration waits
+  /// until the future is completed before continuing with the next element.
+  ///
+  /// Returns a [Future] that completes with `null` when all elements have been
+  /// processed.
+  ///
+  /// Non-[Future] return values, and completion-values of returned [Future]s,
+  /// are discarded.
+  ///
+  /// Any error from [action], synchronous or asynchronous,
+  /// will stop the iteration and be reported in the returned [Future].
   static Future forEach<T>(Iterable<T> elements, FutureOr action(T element)) {
     var iterator = elements.iterator;
     return doWhile(() {
@@ -521,28 +501,26 @@
   // Constant `true` function, used as callback by [forEach].
   static bool _kTrue(Object? _) => true;
 
-  /**
-   * Performs an operation repeatedly until it returns `false`.
-   *
-   * The operation, [action], may be either synchronous or asynchronous.
-   *
-   * The operation is called repeatedly as long as it returns either the [bool]
-   * value `true` or a `Future<bool>` which completes with the value `true`.
-   *
-   * If a call to [action] returns `false` or a [Future] that completes to
-   * `false`, iteration ends and the future returned by [doWhile] is completed
-   * with a `null` value.
-   *
-   * If a call to [action] throws or a future returned by [action] completes
-   * with an error, iteration ends and the future returned by [doWhile]
-   * completes with the same error.
-   *
-   * Calls to [action] may happen at any time,
-   * including immediately after calling `doWhile`.
-   * The only restriction is a new call to [action] won't happen before
-   * the previous call has returned, and if it returned a `Future<bool>`, not
-   * until that future has completed.
-   */
+  /// Performs an operation repeatedly until it returns `false`.
+  ///
+  /// The operation, [action], may be either synchronous or asynchronous.
+  ///
+  /// The operation is called repeatedly as long as it returns either the [bool]
+  /// value `true` or a `Future<bool>` which completes with the value `true`.
+  ///
+  /// If a call to [action] returns `false` or a [Future] that completes to
+  /// `false`, iteration ends and the future returned by [doWhile] is completed
+  /// with a `null` value.
+  ///
+  /// If a call to [action] throws or a future returned by [action] completes
+  /// with an error, iteration ends and the future returned by [doWhile]
+  /// completes with the same error.
+  ///
+  /// Calls to [action] may happen at any time,
+  /// including immediately after calling `doWhile`.
+  /// The only restriction is a new call to [action] won't happen before
+  /// the previous call has returned, and if it returned a `Future<bool>`, not
+  /// until that future has completed.
   static Future doWhile(FutureOr<bool> action()) {
     _Future<void> doneSignal = new _Future<void>();
     late void Function(bool) nextIteration;
@@ -574,88 +552,85 @@
     return doneSignal;
   }
 
-  /**
-   * Register callbacks to be called when this future completes.
-   *
-   * When this future completes with a value,
-   * the [onValue] callback will be called with that value.
-   * If this future is already completed, the callback will not be called
-   * immediately, but will be scheduled in a later microtask.
-   *
-   * If [onError] is provided, and this future completes with an error,
-   * the `onError` callback is called with that error and its stack trace.
-   * The `onError` callback must accept either one argument or two arguments
-   * where the latter is a [StackTrace].
-   * If `onError` accepts two arguments,
-   * it is called with both the error and the stack trace,
-   * otherwise it is called with just the error object.
-   * The `onError` callback must return a value or future that can be used
-   * to complete the returned future, so it must be something assignable to
-   * `FutureOr<R>`.
-   *
-   * Returns a new [Future]
-   * which is completed with the result of the call to `onValue`
-   * (if this future completes with a value)
-   * or to `onError` (if this future completes with an error).
-   *
-   * If the invoked callback throws,
-   * the returned future is completed with the thrown error
-   * and a stack trace for the error.
-   * In the case of `onError`,
-   * if the exception thrown is `identical` to the error argument to `onError`,
-   * the throw is considered a rethrow,
-   * and the original stack trace is used instead.
-   *
-   * If the callback returns a [Future],
-   * the future returned by `then` will be completed with
-   * the same result as the future returned by the callback.
-   *
-   * If [onError] is not given, and this future completes with an error,
-   * the error is forwarded directly to the returned future.
-   *
-   * In most cases, it is more readable to use [catchError] separately, possibly
-   * with a `test` parameter, instead of handling both value and error in a
-   * single [then] call.
-   *
-   * Note that futures don't delay reporting of errors until listeners are
-   * added. If the first `then` or `catchError` call happens after this future
-   * has completed with an error then the error is reported as unhandled error.
-   * See the description on [Future].
-   */
+  /// Register callbacks to be called when this future completes.
+  ///
+  /// When this future completes with a value,
+  /// the [onValue] callback will be called with that value.
+  /// If this future is already completed, the callback will not be called
+  /// immediately, but will be scheduled in a later microtask.
+  ///
+  /// If [onError] is provided, and this future completes with an error,
+  /// the `onError` callback is called with that error and its stack trace.
+  /// The `onError` callback must accept either one argument or two arguments
+  /// where the latter is a [StackTrace].
+  /// If `onError` accepts two arguments,
+  /// it is called with both the error and the stack trace,
+  /// otherwise it is called with just the error object.
+  /// The `onError` callback must return a value or future that can be used
+  /// to complete the returned future, so it must be something assignable to
+  /// `FutureOr<R>`.
+  ///
+  /// Returns a new [Future]
+  /// which is completed with the result of the call to `onValue`
+  /// (if this future completes with a value)
+  /// or to `onError` (if this future completes with an error).
+  ///
+  /// If the invoked callback throws,
+  /// the returned future is completed with the thrown error
+  /// and a stack trace for the error.
+  /// In the case of `onError`,
+  /// if the exception thrown is `identical` to the error argument to `onError`,
+  /// the throw is considered a rethrow,
+  /// and the original stack trace is used instead.
+  ///
+  /// If the callback returns a [Future],
+  /// the future returned by `then` will be completed with
+  /// the same result as the future returned by the callback.
+  ///
+  /// If [onError] is not given, and this future completes with an error,
+  /// the error is forwarded directly to the returned future.
+  ///
+  /// In most cases, it is more readable to use [catchError] separately,
+  /// possibly with a `test` parameter,
+  /// instead of handling both value and error in a single [then] call.
+  ///
+  /// Note that futures don't delay reporting of errors until listeners are
+  /// added. If the first `then` or `catchError` call happens
+  /// after this future has completed with an error,
+  /// then the error is reported as unhandled error.
+  /// See the description on [Future].
   Future<R> then<R>(FutureOr<R> onValue(T value), {Function? onError});
 
-  /**
-   * Handles errors emitted by this [Future].
-   *
-   * This is the asynchronous equivalent of a "catch" block.
-   *
-   * Returns a new [Future] that will be completed with either the result of
-   * this future or the result of calling the `onError` callback.
-   *
-   * If this future completes with a value,
-   * the returned future completes with the same value.
-   *
-   * If this future completes with an error,
-   * then [test] is first called with the error value.
-   *
-   * If `test` returns false, the exception is not handled by this `catchError`,
-   * and the returned future completes with the same error and stack trace
-   * as this future.
-   *
-   * If `test` returns `true`,
-   * [onError] is called with the error and possibly stack trace,
-   * and the returned future is completed with the result of this call
-   * in exactly the same way as for [then]'s `onError`.
-   *
-   * If `test` is omitted, it defaults to a function that always returns true.
-   * The `test` function should not throw, but if it does, it is handled as
-   * if the `onError` function had thrown.
-   *
-   * Note that futures don't delay reporting of errors until listeners are
-   * added. If the first `catchError` (or `then`) call happens after this future
-   * has completed with an error then the error is reported as unhandled error.
-   * See the description on [Future].
-   */
+  /// Handles errors emitted by this [Future].
+  ///
+  /// This is the asynchronous equivalent of a "catch" block.
+  ///
+  /// Returns a new [Future] that will be completed with either the result of
+  /// this future or the result of calling the `onError` callback.
+  ///
+  /// If this future completes with a value,
+  /// the returned future completes with the same value.
+  ///
+  /// If this future completes with an error,
+  /// then [test] is first called with the error value.
+  ///
+  /// If `test` returns false, the exception is not handled by this `catchError`,
+  /// and the returned future completes with the same error and stack trace
+  /// as this future.
+  ///
+  /// If `test` returns `true`,
+  /// [onError] is called with the error and possibly stack trace,
+  /// and the returned future is completed with the result of this call
+  /// in exactly the same way as for [then]'s `onError`.
+  ///
+  /// If `test` is omitted, it defaults to a function that always returns true.
+  /// The `test` function should not throw, but if it does, it is handled as
+  /// if the `onError` function had thrown.
+  ///
+  /// Note that futures don't delay reporting of errors until listeners are
+  /// added. If the first `catchError` (or `then`) call happens after this future
+  /// has completed with an error then the error is reported as unhandled error.
+  /// See the description on [Future].
   // The `Function` below stands for one of two types:
   // - (dynamic) -> FutureOr<T>
   // - (dynamic, StackTrace) -> FutureOr<T>
@@ -663,78 +638,72 @@
   // `isCheck` we should also expect functions that take a specific argument.
   Future<T> catchError(Function onError, {bool test(Object error)?});
 
-  /**
-   * Registers a function to be called when this future completes.
-   *
-   * The [action] function is called when this future completes, whether it
-   * does so with a value or with an error.
-   *
-   * This is the asynchronous equivalent of a "finally" block.
-   *
-   * The future returned by this call, `f`, will complete the same way
-   * as this future unless an error occurs in the [action] call, or in
-   * a [Future] returned by the [action] call. If the call to [action]
-   * does not return a future, its return value is ignored.
-   *
-   * If the call to [action] throws, then `f` is completed with the
-   * thrown error.
-   *
-   * If the call to [action] returns a [Future], `f2`, then completion of
-   * `f` is delayed until `f2` completes. If `f2` completes with
-   * an error, that will be the result of `f` too. The value of `f2` is always
-   * ignored.
-   *
-   * This method is equivalent to:
-   *
-   *     Future<T> whenComplete(action()) {
-   *       return this.then((v) {
-   *         var f2 = action();
-   *         if (f2 is Future) return f2.then((_) => v);
-   *         return v
-   *       }, onError: (e) {
-   *         var f2 = action();
-   *         if (f2 is Future) return f2.then((_) { throw e; });
-   *         throw e;
-   *       });
-   *     }
-   */
+  /// Registers a function to be called when this future completes.
+  ///
+  /// The [action] function is called when this future completes, whether it
+  /// does so with a value or with an error.
+  ///
+  /// This is the asynchronous equivalent of a "finally" block.
+  ///
+  /// The future returned by this call, `f`, will complete the same way
+  /// as this future unless an error occurs in the [action] call, or in
+  /// a [Future] returned by the [action] call. If the call to [action]
+  /// does not return a future, its return value is ignored.
+  ///
+  /// If the call to [action] throws, then `f` is completed with the
+  /// thrown error.
+  ///
+  /// If the call to [action] returns a [Future], `f2`, then completion of
+  /// `f` is delayed until `f2` completes. If `f2` completes with
+  /// an error, that will be the result of `f` too. The value of `f2` is always
+  /// ignored.
+  ///
+  /// This method is equivalent to:
+  /// ```dart
+  /// Future<T> whenComplete(action()) {
+  ///   return this.then((v) {
+  ///     var f2 = action();
+  ///     if (f2 is Future) return f2.then((_) => v);
+  ///     return v
+  ///   }, onError: (e) {
+  ///     var f2 = action();
+  ///     if (f2 is Future) return f2.then((_) { throw e; });
+  ///     throw e;
+  ///   });
+  /// }
+  /// ```
   Future<T> whenComplete(FutureOr<void> action());
 
-  /**
-   * Creates a [Stream] containing the result of this future.
-   *
-   * The stream will produce single data or error event containing the
-   * completion result of this future, and then it will close with a
-   * done event.
-   *
-   * If the future never completes, the stream will not produce any events.
-   */
+  /// Creates a [Stream] containing the result of this future.
+  ///
+  /// The stream will produce single data or error event containing the
+  /// completion result of this future, and then it will close with a
+  /// done event.
+  ///
+  /// If the future never completes, the stream will not produce any events.
   Stream<T> asStream();
 
-  /**
-   * Time-out the future computation after [timeLimit] has passed.
-   *
-   * Returns a new future that completes with the same value as this future,
-   * if this future completes in time.
-   *
-   * If this future does not complete before `timeLimit` has passed,
-   * the [onTimeout] action is executed instead, and its result (whether it
-   * returns or throws) is used as the result of the returned future.
-   * The [onTimeout] function must return a [T] or a `Future<T>`.
-   *
-   * If `onTimeout` is omitted, a timeout will cause the returned future to
-   * complete with a [TimeoutException].
-   */
+  /// Time-out the future computation after [timeLimit] has passed.
+  ///
+  /// Returns a new future that completes with the same value as this future,
+  /// if this future completes in time.
+  ///
+  /// If this future does not complete before `timeLimit` has passed,
+  /// the [onTimeout] action is executed instead, and its result (whether it
+  /// returns or throws) is used as the result of the returned future.
+  /// The [onTimeout] function must return a [T] or a `Future<T>`.
+  ///
+  /// If `onTimeout` is omitted, a timeout will cause the returned future to
+  /// complete with a [TimeoutException].
   Future<T> timeout(Duration timeLimit, {FutureOr<T> onTimeout()?});
 }
 
-/**
- * Thrown when a scheduled timeout happens while waiting for an async result.
- */
+/// Thrown when a scheduled timeout happens while waiting for an async result.
 class TimeoutException implements Exception {
-  /** Description of the cause of the timeout. */
+  /// Description of the cause of the timeout.
   final String? message;
-  /** The duration that was exceeded. */
+
+  /// The duration that was exceeded.
   final Duration? duration;
 
   TimeoutException(this.message, [this.duration]);
@@ -747,183 +716,170 @@
   }
 }
 
-/**
- * A way to produce Future objects and to complete them later
- * with a value or error.
- *
- * Most of the time, the simplest way to create a future is to just use
- * one of the [Future] constructors to capture the result of a single
- * asynchronous computation:
- * ```
- * new Future(() { doSomething(); return result; });
- * ```
- * or, if the future represents the result of a sequence of asynchronous
- * computations, they can be chained using [Future.then] or similar functions
- * on [Future]:
- * ```
- * Future doStuff(){
- *   return someAsyncOperation().then((result) {
- *     return someOtherAsyncOperation(result);
- *   });
- * }
- * ```
- * If you do need to create a Future from scratch — for example,
- * when you're converting a callback-based API into a Future-based
- * one — you can use a Completer as follows:
- * ```
- * class AsyncOperation {
- *   Completer _completer = new Completer();
- *
- *   Future<T> doOperation() {
- *     _startOperation();
- *     return _completer.future; // Send future object back to client.
- *   }
- *
- *   // Something calls this when the value is ready.
- *   void _finishOperation(T result) {
- *     _completer.complete(result);
- *   }
- *
- *   // If something goes wrong, call this.
- *   void _errorHappened(error) {
- *     _completer.completeError(error);
- *   }
- * }
- * ```
- */
+/// A way to produce Future objects and to complete them later
+/// with a value or error.
+///
+/// Most of the time, the simplest way to create a future is to just use
+/// one of the [Future] constructors to capture the result of a single
+/// asynchronous computation:
+/// ```
+/// Future(() { doSomething(); return result; });
+/// ```
+/// or, if the future represents the result of a sequence of asynchronous
+/// computations, they can be chained using [Future.then] or similar functions
+/// on [Future]:
+/// ```
+/// Future doStuff(){
+///   return someAsyncOperation().then((result) {
+///     return someOtherAsyncOperation(result);
+///   });
+/// }
+/// ```
+/// If you do need to create a Future from scratch — for example,
+/// when you're converting a callback-based API into a Future-based
+/// one — you can use a Completer as follows:
+/// ```
+/// class AsyncOperation {
+///   final Completer _completer = new Completer();
+///
+///   Future<T> doOperation() {
+///     _startOperation();
+///     return _completer.future; // Send future object back to client.
+///   }
+///
+///   // Something calls this when the value is ready.
+///   void _finishOperation(T result) {
+///     _completer.complete(result);
+///   }
+///
+///   // If something goes wrong, call this.
+///   void _errorHappened(error) {
+///     _completer.completeError(error);
+///   }
+/// }
+/// ```
 abstract class Completer<T> {
-  /**
-   * Creates a new completer.
-   *
-   * The general workflow for creating a new future is to 1) create a
-   * new completer, 2) hand out its future, and, at a later point, 3) invoke
-   * either [complete] or [completeError].
-   *
-   * The completer completes the future asynchronously. That means that
-   * callbacks registered on the future are not called immediately when
-   * [complete] or [completeError] is called. Instead the callbacks are
-   * delayed until a later microtask.
-   *
-   * Example:
-   * ```
-   * var completer = new Completer();
-   * handOut(completer.future);
-   * later: {
-   *   completer.complete('completion value');
-   * }
-   * ```
-   */
+  /// Creates a new completer.
+  ///
+  /// The general workflow for creating a new future is to 1) create a
+  /// new completer, 2) hand out its future, and, at a later point, 3) invoke
+  /// either [complete] or [completeError].
+  ///
+  /// The completer completes the future asynchronously. That means that
+  /// callbacks registered on the future are not called immediately when
+  /// [complete] or [completeError] is called. Instead the callbacks are
+  /// delayed until a later microtask.
+  ///
+  /// Example:
+  /// ```
+  /// var completer = new Completer();
+  /// handOut(completer.future);
+  /// later: {
+  ///   completer.complete('completion value');
+  /// }
+  /// ```
   factory Completer() => new _AsyncCompleter<T>();
 
-  /**
-   * Completes the future synchronously.
-   *
-   * This constructor should be avoided unless the completion of the future is
-   * known to be the final result of another asynchronous operation. If in doubt
-   * use the default [Completer] constructor.
-   *
-   * Using an normal, asynchronous, completer will never give the wrong
-   * behavior, but using a synchronous completer incorrectly can cause
-   * otherwise correct programs to break.
-   *
-   * A synchronous completer is only intended for optimizing event
-   * propagation when one asynchronous event immediately triggers another.
-   * It should not be used unless the calls to [complete] and [completeError]
-   * are guaranteed to occur in places where it won't break `Future` invariants.
-   *
-   * Completing synchronously means that the completer's future will be
-   * completed immediately when calling the [complete] or [completeError]
-   * method on a synchronous completer, which also calls any callbacks
-   * registered on that future.
-   *
-   * Completing synchronously must not break the rule that when you add a
-   * callback on a future, that callback must not be called until the code
-   * that added the callback has completed.
-   * For that reason, a synchronous completion must only occur at the very end
-   * (in "tail position") of another synchronous event,
-   * because at that point, completing the future immediately is be equivalent
-   * to returning to the event loop and completing the future in the next
-   * microtask.
-   *
-   * Example:
-   *
-   *     var completer = new Completer.sync();
-   *     // The completion is the result of the asynchronous onDone event.
-   *     // No other operation is performed after the completion. It is safe
-   *     // to use the Completer.sync constructor.
-   *     stream.listen(print, onDone: () { completer.complete("done"); });
-   *
-   * Bad example. Do not use this code. Only for illustrative purposes:
-   *
-   *     var completer = new Completer.sync();
-   *     completer.future.then((_) { bar(); });
-   *     // The completion is the result of the asynchronous onDone event.
-   *     // However, there is still code executed after the completion. This
-   *     // operation is *not* safe.
-   *     stream.listen(print, onDone: () {
-   *       completer.complete("done");
-   *       foo();  // In this case, foo() runs after bar().
-   *     });
-   */
+  /// Completes the future synchronously.
+  ///
+  /// This constructor should be avoided unless the completion of the future is
+  /// known to be the final result of another asynchronous operation. If in doubt
+  /// use the default [Completer] constructor.
+  ///
+  /// Using an normal, asynchronous, completer will never give the wrong
+  /// behavior, but using a synchronous completer incorrectly can cause
+  /// otherwise correct programs to break.
+  ///
+  /// A synchronous completer is only intended for optimizing event
+  /// propagation when one asynchronous event immediately triggers another.
+  /// It should not be used unless the calls to [complete] and [completeError]
+  /// are guaranteed to occur in places where it won't break `Future` invariants.
+  ///
+  /// Completing synchronously means that the completer's future will be
+  /// completed immediately when calling the [complete] or [completeError]
+  /// method on a synchronous completer, which also calls any callbacks
+  /// registered on that future.
+  ///
+  /// Completing synchronously must not break the rule that when you add a
+  /// callback on a future, that callback must not be called until the code
+  /// that added the callback has completed.
+  /// For that reason, a synchronous completion must only occur at the very end
+  /// (in "tail position") of another synchronous event,
+  /// because at that point, completing the future immediately is be equivalent
+  /// to returning to the event loop and completing the future in the next
+  /// microtask.
+  ///
+  /// Example:
+  /// ```dart
+  /// var completer = Completer.sync();
+  /// // The completion is the result of the asynchronous onDone event.
+  /// // No other operation is performed after the completion. It is safe
+  /// // to use the Completer.sync constructor.
+  /// stream.listen(print, onDone: () { completer.complete("done"); });
+  /// ```
+  /// Bad example. Do not use this code. Only for illustrative purposes:
+  /// ```dart
+  /// var completer = Completer.sync();
+  /// completer.future.then((_) { bar(); });
+  /// // The completion is the result of the asynchronous onDone event.
+  /// // However, there is still code executed after the completion. This
+  /// // operation is *not* safe.
+  /// stream.listen(print, onDone: () {
+  ///   completer.complete("done");
+  ///   foo();  // In this case, foo() runs after bar().
+  /// });
+  /// ```
   factory Completer.sync() => new _SyncCompleter<T>();
 
-  /**
-   * The future that is completed by this completer.
-   *
-   * The future that is completed when [complete] or [completeError] is called.
-   */
+  /// The future that is completed by this completer.
+  ///
+  /// The future that is completed when [complete] or [completeError] is called.
   Future<T> get future;
 
-  /**
-   * Completes [future] with the supplied values.
-   *
-   * The value must be either a value of type [T]
-   * or a future of type `Future<T>`.
-   * If the value is omitted or null, and `T` is not nullable, the call
-   * to `complete` throws.
-   *
-   * If the value is itself a future, the completer will wait for that future
-   * to complete, and complete with the same result, whether it is a success
-   * or an error.
-   *
-   * Calling [complete] or [completeError] must be done at most once.
-   *
-   * All listeners on the future are informed about the value.
-   */
+  /// Completes [future] with the supplied values.
+  ///
+  /// The value must be either a value of type [T]
+  /// or a future of type `Future<T>`.
+  /// If the value is omitted or `null`, and `T` is not nullable, the call
+  /// to `complete` throws.
+  ///
+  /// If the value is itself a future, the completer will wait for that future
+  /// to complete, and complete with the same result, whether it is a success
+  /// or an error.
+  ///
+  /// Calling [complete] or [completeError] must be done at most once.
+  ///
+  /// All listeners on the future are informed about the value.
   void complete([FutureOr<T>? value]);
 
-  /**
-   * Complete [future] with an error.
-   *
-   * Calling [complete] or [completeError] must be done at most once.
-   *
-   * Completing a future with an error indicates that an exception was thrown
-   * while trying to produce a value.
-   *
-   * If `error` is a `Future`, the future itself is used as the error value.
-   * If you want to complete with the result of the future, you can use:
-   * ```
-   * thisCompleter.complete(theFuture)
-   * ```
-   * or if you only want to handle an error from the future:
-   * ```
-   * theFuture.catchError(thisCompleter.completeError);
-   * ```
-   */
+  /// Complete [future] with an error.
+  ///
+  /// Calling [complete] or [completeError] must be done at most once.
+  ///
+  /// Completing a future with an error indicates that an exception was thrown
+  /// while trying to produce a value.
+  ///
+  /// If `error` is a `Future`, the future itself is used as the error value.
+  /// If you want to complete with the result of the future, you can use:
+  /// ```
+  /// thisCompleter.complete(theFuture)
+  /// ```
+  /// or if you only want to handle an error from the future:
+  /// ```
+  /// theFuture.catchError(thisCompleter.completeError);
+  /// ```
   void completeError(Object error, [StackTrace? stackTrace]);
 
-  /**
-   * Whether the [future] has been completed.
-   *
-   * Reflects whether [complete] or [completeError] has been called.
-   * A `true` value doesn't necessarily mean that listeners of this future
-   * have been invoked yet, either because the completer usually waits until
-   * a later microtask to propagate the result, or because [complete]
-   * was called with a future that hasn't completed yet.
-   *
-   * When this value is `true`, [complete] and [completeError] must not be
-   * called again.
-   */
+  /// Whether the [future] has been completed.
+  ///
+  /// Reflects whether [complete] or [completeError] has been called.
+  /// A `true` value doesn't necessarily mean that listeners of this future
+  /// have been invoked yet, either because the completer usually waits until
+  /// a later microtask to propagate the result, or because [complete]
+  /// was called with a future that hasn't completed yet.
+  ///
+  /// When this value is `true`, [complete] and [completeError] must not be
+  /// called again.
   bool get isCompleted;
 }
 
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index 5b3b77b..df8a347 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -4,11 +4,13 @@
 
 part of dart.async;
 
-/** The onValue and onError handlers return either a value or a future */
+/// The onValue and onError handlers return either a value or a future
 typedef FutureOr<T> _FutureOnValue<S, T>(S value);
-/** Test used by [Future.catchError] to handle skip some errors. */
+
+/// Test used by [Future.catchError] to handle skip some errors.
 typedef bool _FutureErrorTest(Object error);
-/** Used by [WhenFuture]. */
+
+/// Used by [WhenFuture].
 typedef dynamic _FutureAction();
 
 abstract class _Completer<T> implements Completer<T> {
@@ -202,33 +204,29 @@
   /// The future has been completed with an error result.
   static const int _stateError = 8;
 
-  /** Whether the future is complete, and as what. */
+  /// Whether the future is complete, and as what.
   int _state = _stateIncomplete;
 
-  /**
-   * Zone that the future was completed from.
-   * This is the zone that an error result belongs to.
-   *
-   * Until the future is completed, the field may hold the zone that
-   * listener callbacks used to create this future should be run in.
-   */
+  /// Zone that the future was completed from.
+  /// This is the zone that an error result belongs to.
+  ///
+  /// Until the future is completed, the field may hold the zone that
+  /// listener callbacks used to create this future should be run in.
   final _Zone _zone;
 
-  /**
-   * Either the result, a list of listeners or another future.
-   *
-   * The result of the future is either a value or an error.
-   * A result is only stored when the future has completed.
-   *
-   * The listeners is an internally linked list of [_FutureListener]s.
-   * Listeners are only remembered while the future is not yet complete,
-   * and it is not chained to another future.
-   *
-   * The future is another future that his future is chained to. This future
-   * is waiting for the other future to complete, and when it does, this future
-   * will complete with the same result.
-   * All listeners are forwarded to the other future.
-   */
+  /// Either the result, a list of listeners or another future.
+  ///
+  /// The result of the future is either a value or an error.
+  /// A result is only stored when the future has completed.
+  ///
+  /// The listeners is an internally linked list of [_FutureListener]s.
+  /// Listeners are only remembered while the future is not yet complete,
+  /// and it is not chained to another future.
+  ///
+  /// The future is another future that his future is chained to. This future
+  /// is waiting for the other future to complete, and when it does, this future
+  /// will complete with the same result.
+  /// All listeners are forwarded to the other future.
   @pragma("vm:entry-point")
   var _resultOrListeners;
 
@@ -239,7 +237,7 @@
     _asyncComplete(result);
   }
 
-  /** Creates a future with the value and the specified zone. */
+  /// Creates a future with the value and the specified zone.
   _Future.zoneValue(T value, this._zone) {
     _setValue(value);
   }
@@ -249,7 +247,7 @@
     _asyncCompleteError(error, stackTrace);
   }
 
-  /** Creates a future that is already completed with the value. */
+  /// Creates a future that is already completed with the value.
   _Future.value(T value) : this.zoneValue(value, Zone._current);
 
   bool get _mayComplete => _state == _stateIncomplete;
@@ -606,10 +604,8 @@
     });
   }
 
-  /**
-   * Propagates the value/error of [source] to its [listeners], executing the
-   * listeners' callbacks.
-   */
+  /// Propagates the value/error of [source] to its [listeners], executing the
+  /// listeners' callbacks.
   static void _propagateToListeners(
       _Future source, _FutureListener? listeners) {
     while (true) {
diff --git a/sdk/lib/async/schedule_microtask.dart b/sdk/lib/async/schedule_microtask.dart
index d01b483..bb6d600 100644
--- a/sdk/lib/async/schedule_microtask.dart
+++ b/sdk/lib/async/schedule_microtask.dart
@@ -12,24 +12,23 @@
   _AsyncCallbackEntry(this.callback);
 }
 
-/** Head of single linked list of pending callbacks. */
+/// Head of single linked list of pending callbacks.
 _AsyncCallbackEntry? _nextCallback;
-/** Tail of single linked list of pending callbacks. */
+
+/// Tail of single linked list of pending callbacks.
 _AsyncCallbackEntry? _lastCallback;
-/**
- * Tail of priority callbacks added by the currently executing callback.
- *
- * Priority callbacks are put at the beginning of the
- * callback queue, so that if one callback schedules more than one
- * priority callback, they are still enqueued in scheduling order.
- */
+
+/// Tail of priority callbacks added by the currently executing callback.
+///
+/// Priority callbacks are put at the beginning of the
+/// callback queue, so that if one callback schedules more than one
+/// priority callback, they are still enqueued in scheduling order.
 _AsyncCallbackEntry? _lastPriorityCallback;
-/**
- * Whether we are currently inside the callback loop.
- *
- * If we are inside the loop, we never need to schedule the loop,
- * even if adding a first element.
- */
+
+/// Whether we are currently inside the callback loop.
+///
+/// If we are inside the loop, we never need to schedule the loop,
+/// even if adding a first element.
 bool _isInCallbackLoop = false;
 
 void _microtaskLoop() {
@@ -57,12 +56,10 @@
   }
 }
 
-/**
- * Schedules a callback to be called as a microtask.
- *
- * The microtask is called after all other currently scheduled
- * microtasks, but as part of the current system event.
- */
+/// Schedules a callback to be called as a microtask.
+///
+/// The microtask is called after all other currently scheduled
+/// microtasks, but as part of the current system event.
 void _scheduleAsyncCallback(_AsyncCallback callback) {
   _AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback);
   _AsyncCallbackEntry? lastCallback = _lastCallback;
@@ -77,14 +74,12 @@
   }
 }
 
-/**
- * Schedules a callback to be called before all other currently scheduled ones.
- *
- * This callback takes priority over existing scheduled callbacks.
- * It is only used internally to give higher priority to error reporting.
- *
- * Is always run in the root zone.
- */
+/// Schedules a callback to be called before all other currently scheduled ones.
+///
+/// This callback takes priority over existing scheduled callbacks.
+/// It is only used internally to give higher priority to error reporting.
+///
+/// Is always run in the root zone.
 void _schedulePriorityAsyncCallback(_AsyncCallback callback) {
   if (_nextCallback == null) {
     _scheduleAsyncCallback(callback);
@@ -107,32 +102,29 @@
   }
 }
 
-/**
- * Runs a function asynchronously.
- *
- * Callbacks registered through this function are always executed in order and
- * are guaranteed to run before other asynchronous events (like [Timer] events,
- * or DOM events).
- *
- * **Warning:** it is possible to starve the DOM by registering asynchronous
- * callbacks through this method. For example the following program runs
- * the callbacks without ever giving the Timer callback a chance to execute:
- *
- *     main() {
- *       Timer.run(() { print("executed"); });  // Will never be executed.
- *       foo() {
- *         scheduleMicrotask(foo);  // Schedules [foo] in front of other events.
- *       }
- *       foo();
- *     }
- *
- * ## Other resources
- *
- * * [The Event Loop and Dart](https://dart.dev/articles/event-loop/):
- * Learn how Dart handles the event queue and microtask queue, so you can write
- * better asynchronous code with fewer surprises.
- */
-@pragma('vm:entry-point', 'call')
+/// Runs a function asynchronously.
+///
+/// Callbacks registered through this function are always executed in order and
+/// are guaranteed to run before other asynchronous events (like [Timer] events,
+/// or DOM events).
+///
+/// **Warning:** it is possible to starve the DOM by registering asynchronous
+/// callbacks through this method. For example the following program runs
+/// the callbacks without ever giving the Timer callback a chance to execute:
+/// ```dart
+/// main() {
+///   Timer.run(() { print("executed"); });  // Will never be executed.
+///   foo() {
+///     scheduleMicrotask(foo);  // Schedules [foo] in front of other events.
+///   }
+///   foo();
+/// }
+/// ```
+/// ## Other resources
+///
+/// * [The Event Loop and Dart](https://dart.dev/articles/event-loop/):
+/// Learn how Dart handles the event queue and microtask queue, so you can write
+/// better asynchronous code with fewer surprises.
 void scheduleMicrotask(void Function() callback) {
   _Zone currentZone = Zone._current;
   if (identical(_rootZone, currentZone)) {
@@ -152,6 +144,6 @@
 }
 
 class _AsyncRun {
-  /** Schedule the given callback before any other event in the event-loop. */
+  /// Schedule the given callback before any other event in the event-loop.
   external static void _scheduleImmediate(void Function() callback);
 }
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 60f4aa1..f779e02 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -10,114 +10,106 @@
 
 typedef void _TimerCallback();
 
-/**
- * A source of asynchronous data events.
- *
- * A Stream provides a way to receive a sequence of events.
- * Each event is either a data event, also called an *element* of the stream,
- * or an error event, which is a notification that something has failed.
- * When a stream has emitted all its event,
- * a single "done" event will notify the listener that the end has been reached.
- *
- * You [listen] on a stream to make it start generating events,
- * and to set up listeners that receive the events.
- * When you listen, you receive a [StreamSubscription] object
- * which is the active object providing the events,
- * and which can be used to stop listening again,
- * or to temporarily pause events from the subscription.
- *
- * There are two kinds of streams: "Single-subscription" streams and
- * "broadcast" streams.
- *
- * *A single-subscription stream* allows only a single listener during the whole
- * lifetime of the stream.
- * It doesn't start generating events until it has a listener,
- * and it stops sending events when the listener is unsubscribed,
- * even if the source of events could still provide more.
- *
- * Listening twice on a single-subscription stream is not allowed, even after
- * the first subscription has been canceled.
- *
- * Single-subscription streams are generally used for streaming chunks of
- * larger contiguous data like file I/O.
- *
- * *A broadcast stream* allows any number of listeners, and it fires
- * its events when they are ready, whether there are listeners or not.
- *
- * Broadcast streams are used for independent events/observers.
- *
- * If several listeners want to listen to a single subscription stream,
- * use [asBroadcastStream] to create a broadcast stream on top of the
- * non-broadcast stream.
- *
- * On either kind of stream, stream transformations, such as [where] and
- * [skip], return the same type of stream as the one the method was called on,
- * unless otherwise noted.
- *
- * When an event is fired, the listener(s) at that time will receive the event.
- * If a listener is added to a broadcast stream while an event is being fired,
- * that listener will not receive the event currently being fired.
- * If a listener is canceled, it immediately stops receiving events.
- * Listening on a broadcast stream can be treated as listening on a new stream
- * containing only the events that have not yet been emitted when the [listen]
- * call occurs.
- * For example, the [first] getter listens to the stream, then returns the first
- * event that listener receives.
- * This is not necessarily the first even emitted by the stream, but the first
- * of the *remaining* events of the broadcast stream.
- *
- * When the "done" event is fired, subscribers are unsubscribed before
- * receiving the event. After the event has been sent, the stream has no
- * subscribers. Adding new subscribers to a broadcast stream after this point
- * is allowed, but they will just receive a new "done" event as soon
- * as possible.
- *
- * Stream subscriptions always respect "pause" requests. If necessary they need
- * to buffer their input, but often, and preferably, they can simply request
- * their input to pause too.
- *
- * The default implementation of [isBroadcast] returns false.
- * A broadcast stream inheriting from [Stream] must override [isBroadcast]
- * to return `true`.
- */
+/// A source of asynchronous data events.
+///
+/// A Stream provides a way to receive a sequence of events.
+/// Each event is either a data event, also called an *element* of the stream,
+/// or an error event, which is a notification that something has failed.
+/// When a stream has emitted all its event,
+/// a single "done" event will notify the listener that the end has been reached.
+///
+/// You [listen] on a stream to make it start generating events,
+/// and to set up listeners that receive the events.
+/// When you listen, you receive a [StreamSubscription] object
+/// which is the active object providing the events,
+/// and which can be used to stop listening again,
+/// or to temporarily pause events from the subscription.
+///
+/// There are two kinds of streams: "Single-subscription" streams and
+/// "broadcast" streams.
+///
+/// *A single-subscription stream* allows only a single listener during the whole
+/// lifetime of the stream.
+/// It doesn't start generating events until it has a listener,
+/// and it stops sending events when the listener is unsubscribed,
+/// even if the source of events could still provide more.
+///
+/// Listening twice on a single-subscription stream is not allowed, even after
+/// the first subscription has been canceled.
+///
+/// Single-subscription streams are generally used for streaming chunks of
+/// larger contiguous data like file I/O.
+///
+/// *A broadcast stream* allows any number of listeners, and it fires
+/// its events when they are ready, whether there are listeners or not.
+///
+/// Broadcast streams are used for independent events/observers.
+///
+/// If several listeners want to listen to a single subscription stream,
+/// use [asBroadcastStream] to create a broadcast stream on top of the
+/// non-broadcast stream.
+///
+/// On either kind of stream, stream transformations, such as [where] and
+/// [skip], return the same type of stream as the one the method was called on,
+/// unless otherwise noted.
+///
+/// When an event is fired, the listener(s) at that time will receive the event.
+/// If a listener is added to a broadcast stream while an event is being fired,
+/// that listener will not receive the event currently being fired.
+/// If a listener is canceled, it immediately stops receiving events.
+/// Listening on a broadcast stream can be treated as listening on a new stream
+/// containing only the events that have not yet been emitted when the [listen]
+/// call occurs.
+/// For example, the [first] getter listens to the stream, then returns the first
+/// event that listener receives.
+/// This is not necessarily the first even emitted by the stream, but the first
+/// of the *remaining* events of the broadcast stream.
+///
+/// When the "done" event is fired, subscribers are unsubscribed before
+/// receiving the event. After the event has been sent, the stream has no
+/// subscribers. Adding new subscribers to a broadcast stream after this point
+/// is allowed, but they will just receive a new "done" event as soon
+/// as possible.
+///
+/// Stream subscriptions always respect "pause" requests. If necessary they need
+/// to buffer their input, but often, and preferably, they can simply request
+/// their input to pause too.
+///
+/// The default implementation of [isBroadcast] returns false.
+/// A broadcast stream inheriting from [Stream] must override [isBroadcast]
+/// to return `true`.
 abstract class Stream<T> {
   Stream();
 
-  /**
-   * Internal use only. We do not want to promise that Stream stays const.
-   *
-   * If mixins become compatible with const constructors, we may use a
-   * stream mixin instead of extending Stream from a const class.
-   */
+  /// Internal use only. We do not want to promise that Stream stays const.
+  ///
+  /// If mixins become compatible with const constructors, we may use a
+  /// stream mixin instead of extending Stream from a const class.
   const Stream._internal();
 
-  /**
-   * Creates an empty broadcast stream.
-   *
-   * This is a stream which does nothing except sending a done event
-   * when it's listened to.
-   */
+  /// Creates an empty broadcast stream.
+  ///
+  /// This is a stream which does nothing except sending a done event
+  /// when it's listened to.
   const factory Stream.empty() = _EmptyStream<T>;
 
-  /**
-   * Creates a stream which emits a single data event before completing.
-   *
-   * This stream emits a single data event of [value]
-   * and then completes with a done event.
-   *
-   * Example:
-   * ```dart
-   * Future<void> printThings(Stream<String> data) async {
-   *   await for (var x in data) {
-   *     print(x);
-   *   }
-   * }
-   * printThings(Stream<String>.value("ok")); // prints "ok".
-   * ```
-   *
-   * The returned stream is effectively equivalent to one created by
-   * `(() async* { yield value; } ())` or `Future<T>.value(value).asStream()`.
-   */
+  /// Creates a stream which emits a single data event before completing.
+  ///
+  /// This stream emits a single data event of [value]
+  /// and then completes with a done event.
+  ///
+  /// Example:
+  /// ```dart
+  /// Future<void> printThings(Stream<String> data) async {
+  ///   await for (var x in data) {
+  ///     print(x);
+  ///   }
+  /// }
+  /// printThings(Stream<String>.value("ok")); // prints "ok".
+  /// ```
+  ///
+  /// The returned stream is effectively equivalent to one created by
+  /// `(() async* { yield value; } ())` or `Future<T>.value(value).asStream()`.
   @Since("2.5")
   factory Stream.value(T value) =>
       (_AsyncStreamController<T>(null, null, null, null)
@@ -125,30 +117,28 @@
             .._closeUnchecked())
           .stream;
 
-  /**
-   * Creates a stream which emits a single error event before completing.
-   *
-   * This stream emits a single error event of [error] and [stackTrace]
-   * and then completes with a done event.
-   *
-   * Example:
-   * ```dart
-   * Future<void> tryThings(Stream<int> data) async {
-   *   try {
-   *     await for (var x in data) {
-   *       print("Data: $x");
-   *     }
-   *   } catch (e) {
-   *     print(e);
-   *   }
-   * }
-   * tryThings(Stream<int>.error("Error")); // prints "Error".
-   * ```
-   * The returned stream is effectively equivalent to one created by
-   * `Future<T>.error(error, stackTrace).asStream()`, by or
-   * `(() async* { throw error; } ())`, except that you can control the
-   * stack trace as well.
-   */
+  /// Creates a stream which emits a single error event before completing.
+  ///
+  /// This stream emits a single error event of [error] and [stackTrace]
+  /// and then completes with a done event.
+  ///
+  /// Example:
+  /// ```dart
+  /// Future<void> tryThings(Stream<int> data) async {
+  ///   try {
+  ///     await for (var x in data) {
+  ///       print("Data: $x");
+  ///     }
+  ///   } catch (e) {
+  ///     print(e);
+  ///   }
+  /// }
+  /// tryThings(Stream<int>.error("Error")); // prints "Error".
+  /// ```
+  /// The returned stream is effectively equivalent to one created by
+  /// `Future<T>.error(error, stackTrace).asStream()`, by or
+  /// `(() async* { throw error; } ())`, except that you can control the
+  /// stack trace as well.
   @Since("2.5")
   factory Stream.error(Object error, [StackTrace? stackTrace]) {
     // TODO(40614): Remove once non-nullability is sound.
@@ -159,12 +149,10 @@
         .stream;
   }
 
-  /**
-   * Creates a new single-subscription stream from the future.
-   *
-   * When the future completes, the stream will fire one event, either
-   * data or error, and then close with a done-event.
-   */
+  /// Creates a new single-subscription stream from the future.
+  ///
+  /// When the future completes, the stream will fire one event, either
+  /// data or error, and then close with a done-event.
   factory Stream.fromFuture(Future<T> future) {
     // Use the controller's buffering to fill in the value even before
     // the stream has a listener. For a single value, it's not worth it
@@ -181,21 +169,19 @@
     return controller.stream;
   }
 
-  /**
-   * Create a stream from a group of futures.
-   *
-   * The stream reports the results of the futures on the stream in the order
-   * in which the futures complete.
-   * Each future provides either a data event or an error event,
-   * depending on how the future completes.
-   *
-   * If some futures have already completed when `Stream.fromFutures` is called,
-   * their results will be emitted in some unspecified order.
-   *
-   * When all futures have completed, the stream is closed.
-   *
-   * If [futures] is empty, the stream closes as soon as possible.
-   */
+  /// Create a single-subscription stream from a group of futures.
+  ///
+  /// The stream reports the results of the futures on the stream in the order
+  /// in which the futures complete.
+  /// Each future provides either a data event or an error event,
+  /// depending on how the future completes.
+  ///
+  /// If some futures have already completed when `Stream.fromFutures` is called,
+  /// their results will be emitted in some unspecified order.
+  ///
+  /// When all futures have completed, the stream is closed.
+  ///
+  /// If [futures] is empty, the stream closes as soon as possible.
   factory Stream.fromFutures(Iterable<Future<T>> futures) {
     _StreamController<T> controller =
         new _SyncStreamController<T>(null, null, null, null);
@@ -229,109 +215,103 @@
     return controller.stream;
   }
 
-  /**
-   * Creates a single-subscription stream that gets its data from [elements].
-   *
-   * The iterable is iterated when the stream receives a listener, and stops
-   * iterating if the listener cancels the subscription, or if the
-   * [Iterator.moveNext] method returns `false` or throws.
-   * Iteration is suspended while the stream subscription is paused.
-   *
-   * If calling [Iterator.moveNext] on `elements.iterator` throws,
-   * the stream emits that error and then it closes.
-   * If reading [Iterator.current] on `elements.iterator` throws,
-   * the stream emits that error, but keeps iterating.
-   */
+  /// Creates a single-subscription stream that gets its data from [elements].
+  ///
+  /// The iterable is iterated when the stream receives a listener, and stops
+  /// iterating if the listener cancels the subscription, or if the
+  /// [Iterator.moveNext] method returns `false` or throws.
+  /// Iteration is suspended while the stream subscription is paused.
+  ///
+  /// If calling [Iterator.moveNext] on `elements.iterator` throws,
+  /// the stream emits that error and then it closes.
+  /// If reading [Iterator.current] on `elements.iterator` throws,
+  /// the stream emits that error, but keeps iterating.
   factory Stream.fromIterable(Iterable<T> elements) {
     return new _GeneratedStreamImpl<T>(
         () => new _IterablePendingEvents<T>(elements));
   }
 
-  /**
-   * Creates a multi-subscription stream.
-   *
-   * Each time the created stream is listened to,
-   * the [onListen] callback is invoked with a new [MultiStreamController]
-   * which forwards events to the [StreamSubscription]
-   * returned by that [listen] call.
-   *
-   * This allows each listener to be treated as an individual stream.
-   *
-   * The [MultiStreamController] does not support reading its
-   * [StreamController.stream]. Setting its [StreamController.onListen]
-   * has no effect since the [onListen] callback is called instead,
-   * and the [StreamController.onListen] won't be called later.
-   * The controller acts like an asynchronous controller,
-   * but provides extra methods for delivering events synchronously.
-   *
-   * If [isBroadcast] is set to `true`, the returned stream's
-   * [Stream.isBroadcast] will be `true`.
-   * This has no effect on the stream behavior,
-   * it is up to the [onListen] function
-   * to act like a broadcast stream if it claims to be one.
-   *
-   * A multi-subscription stream can behave like any other stream.
-   * If the [onListen] callback throws on every call after the first,
-   * the stream behaves like a single-subscription stream.
-   * If the stream emits the same events to all current listeners,
-   * it behaves like a broadcast stream.
-   *
-   * It can also choose to emit different events to different listeners.
-   * For example, a stream which repeats the most recent
-   * non-`null` event to new listeners, could be implemented as this example:
-   * ```dart
-   * extension StreamRepeatLatestExtension<T extends Object> on Stream<T> {
-   *   Stream<T> repeatLatest() {
-   *     var done = false;
-   *     T? latest = null;
-   *     var currentListeners = <MultiStreamController<T>>{};
-   *     this.listen((event) {
-   *       latest = event;
-   *       for (var listener in [...currentListeners]) listener.addSync(event);
-   *     }, onError: (Object error, StackTrace stack) {
-   *       for (var listener in [...currentListeners]) listener.addErrorSync(error, stack);
-   *     }, onDone: () {
-   *       done = true;
-   *       latest = null;
-   *       for (var listener in currentListeners) listener.closeSync();
-   *       currentListeners.clear();
-   *     });
-   *     return Stream.multi((controller) {
-   *       if (done) {
-   *         controller.close();
-   *         return;
-   *       }
-   *       currentListeners.add(controller);
-   *       var latestValue = latest;
-   *       if (latestValue != null) controller.add(latestValue);
-   *       controller.onCancel = () {
-   *         currentListeners.remove(controller);
-   *       };
-   *     });
-   *   }
-   * }
-   * ```
-   */
+  /// Creates a multi-subscription stream.
+  ///
+  /// Each time the created stream is listened to,
+  /// the [onListen] callback is invoked with a new [MultiStreamController]
+  /// which forwards events to the [StreamSubscription]
+  /// returned by that [listen] call.
+  ///
+  /// This allows each listener to be treated as an individual stream.
+  ///
+  /// The [MultiStreamController] does not support reading its
+  /// [StreamController.stream]. Setting its [StreamController.onListen]
+  /// has no effect since the [onListen] callback is called instead,
+  /// and the [StreamController.onListen] won't be called later.
+  /// The controller acts like an asynchronous controller,
+  /// but provides extra methods for delivering events synchronously.
+  ///
+  /// If [isBroadcast] is set to `true`, the returned stream's
+  /// [Stream.isBroadcast] will be `true`.
+  /// This has no effect on the stream behavior,
+  /// it is up to the [onListen] function
+  /// to act like a broadcast stream if it claims to be one.
+  ///
+  /// A multi-subscription stream can behave like any other stream.
+  /// If the [onListen] callback throws on every call after the first,
+  /// the stream behaves like a single-subscription stream.
+  /// If the stream emits the same events to all current listeners,
+  /// it behaves like a broadcast stream.
+  ///
+  /// It can also choose to emit different events to different listeners.
+  /// For example, a stream which repeats the most recent
+  /// non-`null` event to new listeners, could be implemented as this example:
+  /// ```dart
+  /// extension StreamRepeatLatestExtension<T extends Object> on Stream<T> {
+  ///   Stream<T> repeatLatest() {
+  ///     var done = false;
+  ///     T? latest = null;
+  ///     var currentListeners = <MultiStreamController<T>>{};
+  ///     this.listen((event) {
+  ///       latest = event;
+  ///       for (var listener in [...currentListeners]) listener.addSync(event);
+  ///     }, onError: (Object error, StackTrace stack) {
+  ///       for (var listener in [...currentListeners]) listener.addErrorSync(error, stack);
+  ///     }, onDone: () {
+  ///       done = true;
+  ///       latest = null;
+  ///       for (var listener in currentListeners) listener.closeSync();
+  ///       currentListeners.clear();
+  ///     });
+  ///     return Stream.multi((controller) {
+  ///       if (done) {
+  ///         controller.close();
+  ///         return;
+  ///       }
+  ///       currentListeners.add(controller);
+  ///       var latestValue = latest;
+  ///       if (latestValue != null) controller.add(latestValue);
+  ///       controller.onCancel = () {
+  ///         currentListeners.remove(controller);
+  ///       };
+  ///     });
+  ///   }
+  /// }
+  /// ```
   @Since("2.9")
   factory Stream.multi(void Function(MultiStreamController<T>) onListen,
       {bool isBroadcast = false}) {
     return _MultiStream<T>(onListen, isBroadcast);
   }
 
-  /**
-   * Creates a stream that repeatedly emits events at [period] intervals.
-   *
-   * The event values are computed by invoking [computation]. The argument to
-   * this callback is an integer that starts with 0 and is incremented for
-   * every event.
-   *
-   * The [period] must a non-negative [Duration].
-   *
-   * If [computation] is omitted the event values will all be `null`.
-   *
-   * The [computation] must not be omitted if the event type [T] does not
-   * allow `null` as a value.
-   */
+  /// Creates a stream that repeatedly emits events at [period] intervals.
+  ///
+  /// The event values are computed by invoking [computation]. The argument to
+  /// this callback is an integer that starts with 0 and is incremented for
+  /// every event.
+  ///
+  /// The [period] must a non-negative [Duration].
+  ///
+  /// If [computation] is omitted the event values will all be `null`.
+  ///
+  /// The [computation] must not be omitted if the event type [T] does not
+  /// allow `null` as a value.
   factory Stream.periodic(Duration period,
       [T computation(int computationCount)?]) {
     if (computation == null && !typeAcceptsNull<T>()) {
@@ -381,191 +361,175 @@
     return controller.stream;
   }
 
-  /**
-   * Creates a stream where all events of an existing stream are piped through
-   * a sink-transformation.
-   *
-   * The given [mapSink] closure is invoked when the returned stream is
-   * listened to. All events from the [source] are added into the event sink
-   * that is returned from the invocation. The transformation puts all
-   * transformed events into the sink the [mapSink] closure received during
-   * its invocation. Conceptually the [mapSink] creates a transformation pipe
-   * with the input sink being the returned [EventSink] and the output sink
-   * being the sink it received.
-   *
-   * This constructor is frequently used to build transformers.
-   *
-   * Example use for a duplicating transformer:
-   *
-   *     class DuplicationSink implements EventSink<String> {
-   *       final EventSink<String> _outputSink;
-   *       DuplicationSink(this._outputSink);
-   *
-   *       void add(String data) {
-   *         _outputSink.add(data);
-   *         _outputSink.add(data);
-   *       }
-   *
-   *       void addError(e, [st]) { _outputSink.addError(e, st); }
-   *       void close() { _outputSink.close(); }
-   *     }
-   *
-   *     class DuplicationTransformer extends StreamTransformerBase<String, String> {
-   *       // Some generic types omitted for brevity.
-   *       Stream bind(Stream stream) => new Stream<String>.eventTransformed(
-   *           stream,
-   *           (EventSink sink) => new DuplicationSink(sink));
-   *     }
-   *
-   *     stringStream.transform(new DuplicationTransformer());
-   *
-   * The resulting stream is a broadcast stream if [source] is.
-   */
+  /// Creates a stream where all events of an existing stream are piped through
+  /// a sink-transformation.
+  ///
+  /// The given [mapSink] closure is invoked when the returned stream is
+  /// listened to. All events from the [source] are added into the event sink
+  /// that is returned from the invocation. The transformation puts all
+  /// transformed events into the sink the [mapSink] closure received during
+  /// its invocation. Conceptually the [mapSink] creates a transformation pipe
+  /// with the input sink being the returned [EventSink] and the output sink
+  /// being the sink it received.
+  ///
+  /// This constructor is frequently used to build transformers.
+  ///
+  /// Example use for a duplicating transformer:
+  /// ```dart
+  /// class DuplicationSink implements EventSink<String> {
+  ///   final EventSink<String> _outputSink;
+  ///   DuplicationSink(this._outputSink);
+  ///
+  ///   void add(String data) {
+  ///     _outputSink.add(data);
+  ///     _outputSink.add(data);
+  ///   }
+  ///
+  ///   void addError(e, [st]) { _outputSink.addError(e, st); }
+  ///   void close() { _outputSink.close(); }
+  /// }
+  ///
+  /// class DuplicationTransformer extends StreamTransformerBase<String, String> {
+  ///   // Some generic types omitted for brevity.
+  ///   Stream bind(Stream stream) => Stream<String>.eventTransformed(
+  ///       stream,
+  ///       (EventSink sink) => DuplicationSink(sink));
+  /// }
+  ///
+  /// stringStream.transform(DuplicationTransformer());
+  /// ```
+  /// The resulting stream is a broadcast stream if [source] is.
   factory Stream.eventTransformed(
       Stream<dynamic> source, EventSink<dynamic> mapSink(EventSink<T> sink)) {
     return new _BoundSinkStream(source, mapSink);
   }
 
-  /**
-   * Adapts [source] to be a `Stream<T>`.
-   *
-   * This allows [source] to be used at the new type, but at run-time it
-   * must satisfy the requirements of both the new type and its original type.
-   *
-   * Data events created by the source stream must also be instances of [T].
-   */
+  /// Adapts [source] to be a `Stream<T>`.
+  ///
+  /// This allows [source] to be used at the new type, but at run-time it
+  /// must satisfy the requirements of both the new type and its original type.
+  ///
+  /// Data events created by the source stream must also be instances of [T].
   static Stream<T> castFrom<S, T>(Stream<S> source) =>
       new CastStream<S, T>(source);
 
-  /**
-   * Whether this stream is a broadcast stream.
-   */
+  /// Whether this stream is a broadcast stream.
   bool get isBroadcast => false;
 
-  /**
-   * Returns a multi-subscription stream that produces the same events as this.
-   *
-   * The returned stream will subscribe to this stream when its first
-   * subscriber is added, and will stay subscribed until this stream ends,
-   * or a callback cancels the subscription.
-   *
-   * If [onListen] is provided, it is called with a subscription-like object
-   * that represents the underlying subscription to this stream. It is
-   * possible to pause, resume or cancel the subscription during the call
-   * to [onListen]. It is not possible to change the event handlers, including
-   * using [StreamSubscription.asFuture].
-   *
-   * If [onCancel] is provided, it is called in a similar way to [onListen]
-   * when the returned stream stops having listener. If it later gets
-   * a new listener, the [onListen] function is called again.
-   *
-   * Use the callbacks, for example, for pausing the underlying subscription
-   * while having no subscribers to prevent losing events, or canceling the
-   * subscription when there are no listeners.
-   */
+  /// Returns a multi-subscription stream that produces the same events as this.
+  ///
+  /// The returned stream will subscribe to this stream when its first
+  /// subscriber is added, and will stay subscribed until this stream ends,
+  /// or a callback cancels the subscription.
+  ///
+  /// If [onListen] is provided, it is called with a subscription-like object
+  /// that represents the underlying subscription to this stream. It is
+  /// possible to pause, resume or cancel the subscription during the call
+  /// to [onListen]. It is not possible to change the event handlers, including
+  /// using [StreamSubscription.asFuture].
+  ///
+  /// If [onCancel] is provided, it is called in a similar way to [onListen]
+  /// when the returned stream stops having listener. If it later gets
+  /// a new listener, the [onListen] function is called again.
+  ///
+  /// Use the callbacks, for example, for pausing the underlying subscription
+  /// while having no subscribers to prevent losing events, or canceling the
+  /// subscription when there are no listeners.
   Stream<T> asBroadcastStream(
       {void onListen(StreamSubscription<T> subscription)?,
       void onCancel(StreamSubscription<T> subscription)?}) {
     return new _AsBroadcastStream<T>(this, onListen, onCancel);
   }
 
-  /**
-   * Adds a subscription to this stream.
-   *
-   * Returns a [StreamSubscription] which handles events from this stream using
-   * the provided [onData], [onError] and [onDone] handlers.
-   * The handlers can be changed on the subscription, but they start out
-   * as the provided functions.
-   *
-   * On each data event from this stream, the subscriber's [onData] handler
-   * is called. If [onData] is `null`, nothing happens.
-   *
-   * On errors from this stream, the [onError] handler is called with the
-   * error object and possibly a stack trace.
-   *
-   * The [onError] callback must be of type `void Function(Object error)` or
-   * `void Function(Object error, StackTrace)`.
-   * The function type determines whether [onError] is invoked with a stack
-   * trace argument.
-   * The stack trace argument may be [StackTrace.empty] if this stream received
-   * an error without a stack trace.
-   *
-   * Otherwise it is called with just the error object.
-   * If [onError] is omitted, any errors on this stream are considered unhandled,
-   * and will be passed to the current [Zone]'s error handler.
-   * By default unhandled async errors are treated
-   * as if they were uncaught top-level errors.
-   *
-   * If this stream closes and sends a done event, the [onDone] handler is
-   * called. If [onDone] is `null`, nothing happens.
-   *
-   * If [cancelOnError] is true, the subscription is automatically canceled
-   * when the first error event is delivered. The default is `false`.
-   *
-   * While a subscription is paused, or when it has been canceled,
-   * the subscription doesn't receive events and none of the
-   * event handler functions are called.
-   */
+  /// Adds a subscription to this stream.
+  ///
+  /// Returns a [StreamSubscription] which handles events from this stream using
+  /// the provided [onData], [onError] and [onDone] handlers.
+  /// The handlers can be changed on the subscription, but they start out
+  /// as the provided functions.
+  ///
+  /// On each data event from this stream, the subscriber's [onData] handler
+  /// is called. If [onData] is `null`, nothing happens.
+  ///
+  /// On errors from this stream, the [onError] handler is called with the
+  /// error object and possibly a stack trace.
+  ///
+  /// The [onError] callback must be of type `void Function(Object error)` or
+  /// `void Function(Object error, StackTrace)`.
+  /// The function type determines whether [onError] is invoked with a stack
+  /// trace argument.
+  /// The stack trace argument may be [StackTrace.empty] if this stream received
+  /// an error without a stack trace.
+  ///
+  /// Otherwise it is called with just the error object.
+  /// If [onError] is omitted, any errors on this stream are considered unhandled,
+  /// and will be passed to the current [Zone]'s error handler.
+  /// By default unhandled async errors are treated
+  /// as if they were uncaught top-level errors.
+  ///
+  /// If this stream closes and sends a done event, the [onDone] handler is
+  /// called. If [onDone] is `null`, nothing happens.
+  ///
+  /// If [cancelOnError] is `true`, the subscription is automatically canceled
+  /// when the first error event is delivered. The default is `false`.
+  ///
+  /// While a subscription is paused, or when it has been canceled,
+  /// the subscription doesn't receive events and none of the
+  /// event handler functions are called.
   StreamSubscription<T> listen(void onData(T event)?,
       {Function? onError, void onDone()?, bool? cancelOnError});
 
-  /**
-   * Creates a new stream from this stream that discards some elements.
-   *
-   * The new stream sends the same error and done events as this stream,
-   * but it only sends the data events that satisfy the [test].
-   *
-   * If the [test] function throws, the data event is dropped and the
-   * error is emitted on the returned stream instead.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   * If a broadcast stream is listened to more than once, each subscription
-   * will individually perform the `test`.
-   */
+  /// Creates a new stream from this stream that discards some elements.
+  ///
+  /// The new stream sends the same error and done events as this stream,
+  /// but it only sends the data events that satisfy the [test].
+  ///
+  /// If the [test] function throws, the data event is dropped and the
+  /// error is emitted on the returned stream instead.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
+  /// If a broadcast stream is listened to more than once, each subscription
+  /// will individually perform the `test`.
   Stream<T> where(bool test(T event)) {
     return new _WhereStream<T>(this, test);
   }
 
-  /**
-   * Transforms each element of this stream into a new stream event.
-   *
-   * Creates a new stream that converts each element of this stream
-   * to a new value using the [convert] function, and emits the result.
-   *
-   * For each data event, `o`, in this stream, the returned stream
-   * provides a data event with the value `convert(o)`.
-   * If [convert] throws, the returned stream reports it as an error
-   * event instead.
-   *
-   * Error and done events are passed through unchanged to the returned stream.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   * The [convert] function is called once per data event per listener.
-   * If a broadcast stream is listened to more than once, each subscription
-   * will individually call [convert] on each data event.
-   *
-   * Unlike [transform], this method does not treat the stream as
-   * chunks of a single value. Instead each event is converted independently
-   * of the previous and following events, which may not always be correct.
-   * For example, UTF-8 encoding, or decoding, will give wrong results
-   * if a surrogate pair, or a multibyte UTF-8 encoding, is split into
-   * separate events, and those events are attempted encoded or decoded
-   * independently.
-   */
+  /// Transforms each element of this stream into a new stream event.
+  ///
+  /// Creates a new stream that converts each element of this stream
+  /// to a new value using the [convert] function, and emits the result.
+  ///
+  /// For each data event, `o`, in this stream, the returned stream
+  /// provides a data event with the value `convert(o)`.
+  /// If [convert] throws, the returned stream reports it as an error
+  /// event instead.
+  ///
+  /// Error and done events are passed through unchanged to the returned stream.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
+  /// The [convert] function is called once per data event per listener.
+  /// If a broadcast stream is listened to more than once, each subscription
+  /// will individually call [convert] on each data event.
+  ///
+  /// Unlike [transform], this method does not treat the stream as
+  /// chunks of a single value. Instead each event is converted independently
+  /// of the previous and following events, which may not always be correct.
+  /// For example, UTF-8 encoding, or decoding, will give wrong results
+  /// if a surrogate pair, or a multibyte UTF-8 encoding, is split into
+  /// separate events, and those events are attempted encoded or decoded
+  /// independently.
   Stream<S> map<S>(S convert(T event)) {
     return new _MapStream<T, S>(this, convert);
   }
 
-  /**
-   * Creates a new stream with each data event of this stream asynchronously
-   * mapped to a new event.
-   *
-   * This acts like [map], except that [convert] may return a [Future],
-   * and in that case, this stream waits for that future to complete before
-   * continuing with its result.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   */
+  /// Creates a new stream with each data event of this stream asynchronously
+  /// mapped to a new event.
+  ///
+  /// This acts like [map], except that [convert] may return a [Future],
+  /// and in that case, this stream waits for that future to complete before
+  /// continuing with its result.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
   Stream<E> asyncMap<E>(FutureOr<E> convert(T event)) {
     _StreamControllerBase<E> controller;
     if (isBroadcast) {
@@ -610,24 +574,22 @@
     return controller.stream;
   }
 
-  /**
-   * Transforms each element into a sequence of asynchronous events.
-   *
-   * Returns a new stream and for each event of this stream, do the following:
-   *
-   * * If the event is an error event or a done event, it is emitted directly
-   * by the returned stream.
-   * * Otherwise it is an element. Then the [convert] function is called
-   * with the element as argument to produce a convert-stream for the element.
-   * * If that call throws, the error is emitted on the returned stream.
-   * * If the call returns `null`, no further action is taken for the elements.
-   * * Otherwise, this stream is paused and convert-stream is listened to.
-   * Every data and error event of the convert-stream is emitted on the returned
-   * stream in the order it is produced.
-   * When the convert-stream ends, this stream is resumed.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   */
+  /// Transforms each element into a sequence of asynchronous events.
+  ///
+  /// Returns a new stream and for each event of this stream, do the following:
+  ///
+  /// * If the event is an error event or a done event, it is emitted directly
+  /// by the returned stream.
+  /// * Otherwise it is an element. Then the [convert] function is called
+  /// with the element as argument to produce a convert-stream for the element.
+  /// * If that call throws, the error is emitted on the returned stream.
+  /// * If the call returns `null`, no further action is taken for the elements.
+  /// * Otherwise, this stream is paused and convert-stream is listened to.
+  /// Every data and error event of the convert-stream is emitted on the returned
+  /// stream in the order it is produced.
+  /// When the convert-stream ends, this stream is resumed.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
   Stream<E> asyncExpand<E>(Stream<E>? convert(T event)) {
     _StreamControllerBase<E> controller;
     if (isBroadcast) {
@@ -663,135 +625,125 @@
     return controller.stream;
   }
 
-  /**
-   * Creates a wrapper Stream that intercepts some errors from this stream.
-   *
-   * If this stream sends an error that matches [test], then it is intercepted
-   * by the [onError] function.
-   *
-   * The [onError] callback must be of type `void Function(Object error)` or
-   * `void Function(Object error, StackTrace)`.
-   * The function type determines whether [onError] is invoked with a stack
-   * trace argument.
-   * The stack trace argument may be [StackTrace.empty] if this stream received
-   * an error without a stack trace.
-   *
-   * An asynchronous error `error` is matched by a test function if
-   *`test(error)` returns true. If [test] is omitted, every error is considered
-   * matching.
-   *
-   * If the error is intercepted, the [onError] function can decide what to do
-   * with it. It can throw if it wants to raise a new (or the same) error,
-   * or simply return to make this stream forget the error.
-   * If the received `error` value is thrown again by the [onError] function,
-   * it acts like a `rethrow` and it is emitted along with its original
-   * stack trace, not the stack trace of the `throw` inside [onError].
-   *
-   * If you need to transform an error into a data event, use the more generic
-   * [Stream.transform] to handle the event by writing a data event to
-   * the output sink.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   * If a broadcast stream is listened to more than once, each subscription
-   * will individually perform the `test` and handle the error.
-   */
+  /// Creates a wrapper Stream that intercepts some errors from this stream.
+  ///
+  /// If this stream sends an error that matches [test], then it is intercepted
+  /// by the [onError] function.
+  ///
+  /// The [onError] callback must be of type `void Function(Object error)` or
+  /// `void Function(Object error, StackTrace)`.
+  /// The function type determines whether [onError] is invoked with a stack
+  /// trace argument.
+  /// The stack trace argument may be [StackTrace.empty] if this stream received
+  /// an error without a stack trace.
+  ///
+  /// An asynchronous error `error` is matched by a test function if
+  ///`test(error)` returns true. If [test] is omitted, every error is considered
+  /// matching.
+  ///
+  /// If the error is intercepted, the [onError] function can decide what to do
+  /// with it. It can throw if it wants to raise a new (or the same) error,
+  /// or simply return to make this stream forget the error.
+  /// If the received `error` value is thrown again by the [onError] function,
+  /// it acts like a `rethrow` and it is emitted along with its original
+  /// stack trace, not the stack trace of the `throw` inside [onError].
+  ///
+  /// If you need to transform an error into a data event, use the more generic
+  /// [Stream.transform] to handle the event by writing a data event to
+  /// the output sink.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
+  /// If a broadcast stream is listened to more than once, each subscription
+  /// will individually perform the `test` and handle the error.
   Stream<T> handleError(Function onError, {bool test(error)?}) {
     return new _HandleErrorStream<T>(this, onError, test);
   }
 
-  /**
-   * Transforms each element of this stream into a sequence of elements.
-   *
-   * Returns a new stream where each element of this stream is replaced
-   * by zero or more data events.
-   * The event values are provided as an [Iterable] by a call to [convert]
-   * with the element as argument, and the elements of that iterable is
-   * emitted in iteration order.
-   * If calling [convert] throws, or if the iteration of the returned values
-   * throws, the error is emitted on the returned stream and iteration ends
-   * for that element of this stream.
-   *
-   * Error events and the done event of this stream are forwarded directly
-   * to the returned stream.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   * If a broadcast stream is listened to more than once, each subscription
-   * will individually call `convert` and expand the events.
-   */
+  /// Transforms each element of this stream into a sequence of elements.
+  ///
+  /// Returns a new stream where each element of this stream is replaced
+  /// by zero or more data events.
+  /// The event values are provided as an [Iterable] by a call to [convert]
+  /// with the element as argument, and the elements of that iterable is
+  /// emitted in iteration order.
+  /// If calling [convert] throws, or if the iteration of the returned values
+  /// throws, the error is emitted on the returned stream and iteration ends
+  /// for that element of this stream.
+  ///
+  /// Error events and the done event of this stream are forwarded directly
+  /// to the returned stream.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
+  /// If a broadcast stream is listened to more than once, each subscription
+  /// will individually call `convert` and expand the events.
   Stream<S> expand<S>(Iterable<S> convert(T element)) {
     return new _ExpandStream<T, S>(this, convert);
   }
 
-  /**
-   * Pipes the events of this stream into [streamConsumer].
-   *
-   * All events of this stream are added to `streamConsumer` using
-   * [StreamConsumer.addStream].
-   * The `streamConsumer` is closed when this stream has been successfully added
-   * to it - when the future returned by `addStream` completes without an error.
-   *
-   * Returns a future which completes when this stream has been consumed
-   * and the consumer has been closed.
-   *
-   * The returned future completes with the same result as the future returned
-   * by [StreamConsumer.close].
-   * If the call to [StreamConsumer.addStream] fails in some way, this
-   * method fails in the same way.
-   */
+  /// Pipes the events of this stream into [streamConsumer].
+  ///
+  /// All events of this stream are added to `streamConsumer` using
+  /// [StreamConsumer.addStream].
+  /// The `streamConsumer` is closed when this stream has been successfully added
+  /// to it - when the future returned by `addStream` completes without an error.
+  ///
+  /// Returns a future which completes when this stream has been consumed
+  /// and the consumer has been closed.
+  ///
+  /// The returned future completes with the same result as the future returned
+  /// by [StreamConsumer.close].
+  /// If the call to [StreamConsumer.addStream] fails in some way, this
+  /// method fails in the same way.
   Future pipe(StreamConsumer<T> streamConsumer) {
     return streamConsumer.addStream(this).then((_) => streamConsumer.close());
   }
 
-  /**
-   * Applies [streamTransformer] to this stream.
-   *
-   * Returns the transformed stream,
-   * that is, the result of `streamTransformer.bind(this)`.
-   * This method simply allows writing the call to `streamTransformer.bind`
-   * in a chained fashion, like
-   * ```
-   * stream.map(mapping).transform(transformation).toList()
-   * ```
-   * which can be more convenient than calling `bind` directly.
-   *
-   * The [streamTransformer] can return any stream.
-   * Whether the returned stream is a broadcast stream or not,
-   * and which elements it will contain,
-   * is entirely up to the transformation.
-   *
-   * This method should always be used for transformations which treat
-   * the entire stream as representing a single value
-   * which has perhaps been split into several parts for transport,
-   * like a file being read from disk or being fetched over a network.
-   * The transformation will then produce a new stream which
-   * transforms the stream's value incrementally (perhaps using
-   * [Converter.startChunkedConversion]). The resulting stream
-   * may again be chunks of the result, but does not have to
-   * correspond to specific events from the source string.
-   */
+  /// Applies [streamTransformer] to this stream.
+  ///
+  /// Returns the transformed stream,
+  /// that is, the result of `streamTransformer.bind(this)`.
+  /// This method simply allows writing the call to `streamTransformer.bind`
+  /// in a chained fashion, like
+  /// ```
+  /// stream.map(mapping).transform(transformation).toList()
+  /// ```
+  /// which can be more convenient than calling `bind` directly.
+  ///
+  /// The [streamTransformer] can return any stream.
+  /// Whether the returned stream is a broadcast stream or not,
+  /// and which elements it will contain,
+  /// is entirely up to the transformation.
+  ///
+  /// This method should always be used for transformations which treat
+  /// the entire stream as representing a single value
+  /// which has perhaps been split into several parts for transport,
+  /// like a file being read from disk or being fetched over a network.
+  /// The transformation will then produce a new stream which
+  /// transforms the stream's value incrementally (perhaps using
+  /// [Converter.startChunkedConversion]). The resulting stream
+  /// may again be chunks of the result, but does not have to
+  /// correspond to specific events from the source string.
   Stream<S> transform<S>(StreamTransformer<T, S> streamTransformer) {
     return streamTransformer.bind(this);
   }
 
-  /**
-   * Combines a sequence of values by repeatedly applying [combine].
-   *
-   * Similar to [Iterable.reduce], this function maintains a value,
-   * starting with the first element of this stream
-   * and updated for each further element of this stream.
-   * For each element after the first,
-   * the value is updated to the result of calling [combine]
-   * with the previous value and the element.
-   *
-   * When this stream is done, the returned future is completed with
-   * the value at that time.
-   *
-   * If this stream is empty, the returned future is completed with
-   * an error.
-   * If this stream emits an error, or the call to [combine] throws,
-   * the returned future is completed with that error,
-   * and processing is stopped.
-   */
+  /// Combines a sequence of values by repeatedly applying [combine].
+  ///
+  /// Similar to [Iterable.reduce], this function maintains a value,
+  /// starting with the first element of this stream
+  /// and updated for each further element of this stream.
+  /// For each element after the first,
+  /// the value is updated to the result of calling [combine]
+  /// with the previous value and the element.
+  ///
+  /// When this stream is done, the returned future is completed with
+  /// the value at that time.
+  ///
+  /// If this stream is empty, the returned future is completed with
+  /// an error.
+  /// If this stream emits an error, or the call to [combine] throws,
+  /// the returned future is completed with that error,
+  /// and processing is stopped.
   Future<T> reduce(T combine(T previous, T element)) {
     _Future<T> result = new _Future<T>();
     bool seenFirst = false;
@@ -824,23 +776,21 @@
     return result;
   }
 
-  /**
-   * Combines a sequence of values by repeatedly applying [combine].
-   *
-   * Similar to [Iterable.fold], this function maintains a value,
-   * starting with [initialValue] and updated for each element of
-   * this stream.
-   * For each element, the value is updated to the result of calling
-   * [combine] with the previous value and the element.
-   *
-   * When this stream is done, the returned future is completed with
-   * the value at that time.
-   * For an empty stream, the future is completed with [initialValue].
-   *
-   * If this stream emits an error, or the call to [combine] throws,
-   * the returned future is completed with that error,
-   * and processing is stopped.
-   */
+  /// Combines a sequence of values by repeatedly applying [combine].
+  ///
+  /// Similar to [Iterable.fold], this function maintains a value,
+  /// starting with [initialValue] and updated for each element of
+  /// this stream.
+  /// For each element, the value is updated to the result of calling
+  /// [combine] with the previous value and the element.
+  ///
+  /// When this stream is done, the returned future is completed with
+  /// the value at that time.
+  /// For an empty stream, the future is completed with [initialValue].
+  ///
+  /// If this stream emits an error, or the call to [combine] throws,
+  /// the returned future is completed with that error,
+  /// and processing is stopped.
   Future<S> fold<S>(S initialValue, S combine(S previous, T element)) {
     _Future<S> result = new _Future<S>();
     S value = initialValue;
@@ -856,20 +806,18 @@
     return result;
   }
 
-  /**
-   * Combines the string representation of elements into a single string.
-   *
-   * Each element is converted to a string using its [Object.toString] method.
-   * If [separator] is provided, it is inserted between element string
-   * representations.
-   *
-   * The returned future is completed with the combined string when this stream
-   * is done.
-   *
-   * If this stream emits an error, or the call to [Object.toString] throws,
-   * the returned future is completed with that error,
-   * and processing stops.
-   */
+  /// Combines the string representation of elements into a single string.
+  ///
+  /// Each element is converted to a string using its [Object.toString] method.
+  /// If [separator] is provided, it is inserted between element string
+  /// representations.
+  ///
+  /// The returned future is completed with the combined string when this stream
+  /// is done.
+  ///
+  /// If this stream emits an error, or the call to [Object.toString] throws,
+  /// the returned future is completed with that error,
+  /// and processing stops.
   Future<String> join([String separator = ""]) {
     _Future<String> result = new _Future<String>();
     StringBuffer buffer = new StringBuffer();
@@ -900,18 +848,16 @@
     return result;
   }
 
-  /**
-   * Returns whether [needle] occurs in the elements provided by this stream.
-   *
-   * Compares each element of this stream to [needle] using [Object.==].
-   * If an equal element is found, the returned future is completed with `true`.
-   * If this stream ends without finding a match, the future is completed with
-   * `false`.
-   *
-   * If this stream emits an error, or the call to [Object.==] throws,
-   * the returned future is completed with that error,
-   * and processing stops.
-   */
+  /// Returns whether [needle] occurs in the elements provided by this stream.
+  ///
+  /// Compares each element of this stream to [needle] using [Object.==].
+  /// If an equal element is found, the returned future is completed with `true`.
+  /// If this stream ends without finding a match, the future is completed with
+  /// `false`.
+  ///
+  /// If this stream emits an error, or the call to [Object.==] throws,
+  /// the returned future is completed with that error,
+  /// and processing stops.
   Future<bool> contains(Object? needle) {
     _Future<bool> future = new _Future<bool>();
     StreamSubscription<T> subscription =
@@ -928,16 +874,14 @@
     return future;
   }
 
-  /**
-   * Executes [action] on each element of this stream.
-   *
-   * Completes the returned [Future] when all elements of this stream
-   * have been processed.
-   *
-   * If this stream emits an error, or if the call to [action] throws,
-   * the returned future completes with that error,
-   * and processing stops.
-   */
+  /// Executes [action] on each element of this stream.
+  ///
+  /// Completes the returned [Future] when all elements of this stream
+  /// have been processed.
+  ///
+  /// If this stream emits an error, or if the call to [action] throws,
+  /// the returned future completes with that error,
+  /// and processing stops.
   Future forEach(void action(T element)) {
     _Future future = new _Future();
     StreamSubscription<T> subscription =
@@ -951,20 +895,18 @@
     return future;
   }
 
-  /**
-   * Checks whether [test] accepts all elements provided by this stream.
-   *
-   * Calls [test] on each element of this stream.
-   * If the call returns `false`, the returned future is completed with `false`
-   * and processing stops.
-   *
-   * If this stream ends without finding an element that [test] rejects,
-   * the returned future is completed with `true`.
-   *
-   * If this stream emits an error, or if the call to [test] throws,
-   * the returned future is completed with that error,
-   * and processing stops.
-   */
+  /// Checks whether [test] accepts all elements provided by this stream.
+  ///
+  /// Calls [test] on each element of this stream.
+  /// If the call returns `false`, the returned future is completed with `false`
+  /// and processing stops.
+  ///
+  /// If this stream ends without finding an element that [test] rejects,
+  /// the returned future is completed with `true`.
+  ///
+  /// If this stream emits an error, or if the call to [test] throws,
+  /// the returned future is completed with that error,
+  /// and processing stops.
   Future<bool> every(bool test(T element)) {
     _Future<bool> future = new _Future<bool>();
     StreamSubscription<T> subscription =
@@ -981,20 +923,18 @@
     return future;
   }
 
-  /**
-   * Checks whether [test] accepts any element provided by this stream.
-   *
-   * Calls [test] on each element of this stream.
-   * If the call returns `true`, the returned future is completed with `true`
-   * and processing stops.
-   *
-   * If this stream ends without finding an element that [test] accepts,
-   * the returned future is completed with `false`.
-   *
-   * If this stream emits an error, or if the call to [test] throws,
-   * the returned future is completed with that error,
-   * and processing stops.
-   */
+  /// Checks whether [test] accepts any element provided by this stream.
+  ///
+  /// Calls [test] on each element of this stream.
+  /// If the call returns `true`, the returned future is completed with `true`
+  /// and processing stops.
+  ///
+  /// If this stream ends without finding an element that [test] accepts,
+  /// the returned future is completed with `false`.
+  ///
+  /// If this stream emits an error, or if the call to [test] throws,
+  /// the returned future is completed with that error,
+  /// and processing stops.
   Future<bool> any(bool test(T element)) {
     _Future<bool> future = new _Future<bool>();
     StreamSubscription<T> subscription =
@@ -1011,19 +951,17 @@
     return future;
   }
 
-  /**
-   * The number of elements in this stream.
-   *
-   * Waits for all elements of this stream. When this stream ends,
-   * the returned future is completed with the number of elements.
-   *
-   * If this stream emits an error,
-   * the returned future is completed with that error,
-   * and processing stops.
-   *
-   * This operation listens to this stream, and a non-broadcast stream cannot
-   * be reused after finding its length.
-   */
+  /// The number of elements in this stream.
+  ///
+  /// Waits for all elements of this stream. When this stream ends,
+  /// the returned future is completed with the number of elements.
+  ///
+  /// If this stream emits an error,
+  /// the returned future is completed with that error,
+  /// and processing stops.
+  ///
+  /// This operation listens to this stream, and a non-broadcast stream cannot
+  /// be reused after finding its length.
   Future<int> get length {
     _Future<int> future = new _Future<int>();
     int count = 0;
@@ -1039,20 +977,18 @@
     return future;
   }
 
-  /**
-   * Whether this stream contains any elements.
-   *
-   * Waits for the first element of this stream, then completes the returned
-   * future with `false`.
-   * If this stream ends without emitting any elements, the returned future is
-   * completed with `true`.
-   *
-   * If the first event is an error, the returned future is completed with that
-   * error.
-   *
-   * This operation listens to this stream, and a non-broadcast stream cannot
-   * be reused after checking whether it is empty.
-   */
+  /// Whether this stream contains any elements.
+  ///
+  /// Waits for the first element of this stream, then completes the returned
+  /// future with `false`.
+  /// If this stream ends without emitting any elements, the returned future is
+  /// completed with `true`.
+  ///
+  /// If the first event is an error, the returned future is completed with that
+  /// error.
+  ///
+  /// This operation listens to this stream, and a non-broadcast stream cannot
+  /// be reused after checking whether it is empty.
   Future<bool> get isEmpty {
     _Future<bool> future = new _Future<bool>();
     StreamSubscription<T> subscription =
@@ -1065,24 +1001,21 @@
     return future;
   }
 
-  /**
-   * Adapt this stream to be a `Stream<R>`.
-   *
-   * This stream is wrapped as a `Stream<R>` which checks at run-time that
-   * each data event emitted by this stream is also an instance of [R].
-   */
+  /// Adapt this stream to be a `Stream<R>`.
+  ///
+  /// This stream is wrapped as a `Stream<R>` which checks at run-time that
+  /// each data event emitted by this stream is also an instance of [R].
   Stream<R> cast<R>() => Stream.castFrom<T, R>(this);
-  /**
-   * Collects all elements of this stream in a [List].
-   *
-   * Creates a `List<T>` and adds all elements of this stream to the list
-   * in the order they arrive.
-   * When this stream ends, the returned future is completed with that list.
-   *
-   * If this stream emits an error,
-   * the returned future is completed with that error,
-   * and processing stops.
-   */
+
+  /// Collects all elements of this stream in a [List].
+  ///
+  /// Creates a `List<T>` and adds all elements of this stream to the list
+  /// in the order they arrive.
+  /// When this stream ends, the returned future is completed with that list.
+  ///
+  /// If this stream emits an error,
+  /// the returned future is completed with that error,
+  /// and processing stops.
   Future<List<T>> toList() {
     List<T> result = <T>[];
     _Future<List<T>> future = new _Future<List<T>>();
@@ -1098,23 +1031,21 @@
     return future;
   }
 
-  /**
-   * Collects the data of this stream in a [Set].
-   *
-   * Creates a `Set<T>` and adds all elements of this stream to the set.
-   * in the order they arrive.
-   * When this stream ends, the returned future is completed with that set.
-   *
-   * The returned set is the same type as returned by `new Set<T>()`.
-   * If another type of set is needed, either use [forEach] to add each
-   * element to the set, or use
-   * `toList().then((list) => new SomeOtherSet.from(list))`
-   * to create the set.
-   *
-   * If this stream emits an error,
-   * the returned future is completed with that error,
-   * and processing stops.
-   */
+  /// Collects the data of this stream in a [Set].
+  ///
+  /// Creates a `Set<T>` and adds all elements of this stream to the set.
+  /// in the order they arrive.
+  /// When this stream ends, the returned future is completed with that set.
+  ///
+  /// The returned set is the same type as created by `<T>{}`.
+  /// If another type of set is needed, either use [forEach] to add each
+  /// element to the set, or use
+  /// `toList().then((list) => new SomeOtherSet.from(list))`
+  /// to create the set.
+  ///
+  /// If this stream emits an error,
+  /// the returned future is completed with that error,
+  /// and processing stops.
   Future<Set<T>> toSet() {
     Set<T> result = new Set<T>();
     _Future<Set<T>> future = new _Future<Set<T>>();
@@ -1130,22 +1061,20 @@
     return future;
   }
 
-  /**
-   * Discards all data on this stream, but signals when it is done or an error
-   * occurred.
-   *
-   * When subscribing using [drain], cancelOnError will be true. This means
-   * that the future will complete with the first error on this stream and then
-   * cancel the subscription.
-   *
-   * If this stream emits an error, the returned future is completed with
-   * that error, and processing is stopped.
-   *
-   * In case of a `done` event the future completes with the given
-   * [futureValue].
-   *
-   * The [futureValue] must not be omitted if `null` is not assignable to [E].
-   */
+  /// Discards all data on this stream, but signals when it is done or an error
+  /// occurred.
+  ///
+  /// When subscribing using [drain], cancelOnError will be true. This means
+  /// that the future will complete with the first error on this stream and then
+  /// cancel the subscription.
+  ///
+  /// If this stream emits an error, the returned future is completed with
+  /// that error, and processing is stopped.
+  ///
+  /// In case of a `done` event the future completes with the given
+  /// [futureValue].
+  ///
+  /// The [futureValue] must not be omitted if `null` is not assignable to [E].
   Future<E> drain<E>([E? futureValue]) {
     if (futureValue == null) {
       futureValue = futureValue as E;
@@ -1153,141 +1082,129 @@
     return listen(null, cancelOnError: true).asFuture<E>(futureValue);
   }
 
-  /**
-   * Provides at most the first [count] data events of this stream.
-   *
-   * Returns a stream that emits the same events that this stream would
-   * if listened to at the same time,
-   * until either this stream ends or it has emitted [count] data events,
-   * at which point the returned stream is done.
-   *
-   * If this stream produces fewer than [count] data events before it's done,
-   * so will the returned stream.
-   *
-   * Starts listening to this stream when the returned stream is listened to
-   * and stops listening when the first [count] data events have been received.
-   *
-   * This means that if this is a single-subscription (non-broadcast) streams
-   * it cannot be reused after the returned stream has been listened to.
-   *
-   * If this is a broadcast stream, the returned stream is a broadcast stream.
-   * In that case, the events are only counted from the time
-   * the returned stream is listened to.
-   */
+  /// Provides at most the first [count] data events of this stream.
+  ///
+  /// Returns a stream that emits the same events that this stream would
+  /// if listened to at the same time,
+  /// until either this stream ends or it has emitted [count] data events,
+  /// at which point the returned stream is done.
+  ///
+  /// If this stream produces fewer than [count] data events before it's done,
+  /// so will the returned stream.
+  ///
+  /// Starts listening to this stream when the returned stream is listened to
+  /// and stops listening when the first [count] data events have been received.
+  ///
+  /// This means that if this is a single-subscription (non-broadcast) streams
+  /// it cannot be reused after the returned stream has been listened to.
+  ///
+  /// If this is a broadcast stream, the returned stream is a broadcast stream.
+  /// In that case, the events are only counted from the time
+  /// the returned stream is listened to.
   Stream<T> take(int count) {
     return new _TakeStream<T>(this, count);
   }
 
-  /**
-   * Forwards data events while [test] is successful.
-   *
-   * Returns a stream that provides the same events as this stream
-   * until [test] fails for a data event.
-   * The returned stream is done when either this stream is done,
-   * or when this stream first emits a data event that fails [test].
-   *
-   * The `test` call is considered failing if it returns a non-`true` value
-   * or if it throws. If the `test` call throws, the error is emitted as the
-   * last event on the returned streams.
-   *
-   * Stops listening to this stream after the accepted elements.
-   *
-   * Internally the method cancels its subscription after these elements. This
-   * means that single-subscription (non-broadcast) streams are closed and
-   * cannot be reused after a call to this method.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   * For a broadcast stream, the events are only tested from the time
-   * the returned stream is listened to.
-   */
+  /// Forwards data events while [test] is successful.
+  ///
+  /// Returns a stream that provides the same events as this stream
+  /// until [test] fails for a data event.
+  /// The returned stream is done when either this stream is done,
+  /// or when this stream first emits a data event that fails [test].
+  ///
+  /// The `test` call is considered failing if it returns a non-`true` value
+  /// or if it throws. If the `test` call throws, the error is emitted as the
+  /// last event on the returned streams.
+  ///
+  /// Stops listening to this stream after the accepted elements.
+  ///
+  /// Internally the method cancels its subscription after these elements. This
+  /// means that single-subscription (non-broadcast) streams are closed and
+  /// cannot be reused after a call to this method.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
+  /// For a broadcast stream, the events are only tested from the time
+  /// the returned stream is listened to.
   Stream<T> takeWhile(bool test(T element)) {
     return new _TakeWhileStream<T>(this, test);
   }
 
-  /**
-   * Skips the first [count] data events from this stream.
-   *
-   * Returns a stream that emits the same events as this stream would
-   * if listened to at the same time, except that the first [count]
-   * data events are not emitted.
-   * The returned stream is done when this stream is.
-   *
-   * If this stream emits fewer than [count] data events
-   * before being done, the returned stream emits no data events.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   * For a broadcast stream, the events are only counted from the time
-   * the returned stream is listened to.
-   */
+  /// Skips the first [count] data events from this stream.
+  ///
+  /// Returns a stream that emits the same events as this stream would
+  /// if listened to at the same time, except that the first [count]
+  /// data events are not emitted.
+  /// The returned stream is done when this stream is.
+  ///
+  /// If this stream emits fewer than [count] data events
+  /// before being done, the returned stream emits no data events.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
+  /// For a broadcast stream, the events are only counted from the time
+  /// the returned stream is listened to.
   Stream<T> skip(int count) {
     return new _SkipStream<T>(this, count);
   }
 
-  /**
-   * Skip data events from this stream while they are matched by [test].
-   *
-   * Returns a stream that emits the same events as this stream,
-   * except that data events are not emitted until a data event fails `test`.
-   * The test fails when called with a data event
-   * if it returns a non-`true` value or if the call to `test` throws.
-   * If the call throws, the error is emitted as an error event
-   * on the returned stream instead of the data event,
-   * otherwise the event that made `test` return non-true is emitted as the
-   * first data event.
-   *
-   * Error and done events are provided by the returned stream unmodified.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   * For a broadcast stream, the events are only tested from the time
-   * the returned stream is listened to.
-   */
+  /// Skip data events from this stream while they are matched by [test].
+  ///
+  /// Returns a stream that emits the same events as this stream,
+  /// except that data events are not emitted until a data event fails `test`.
+  /// The test fails when called with a data event
+  /// if it returns a non-`true` value or if the call to `test` throws.
+  /// If the call throws, the error is emitted as an error event
+  /// on the returned stream instead of the data event,
+  /// otherwise the event that made `test` return non-true is emitted as the
+  /// first data event.
+  ///
+  /// Error and done events are provided by the returned stream unmodified.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
+  /// For a broadcast stream, the events are only tested from the time
+  /// the returned stream is listened to.
   Stream<T> skipWhile(bool test(T element)) {
     return new _SkipWhileStream<T>(this, test);
   }
 
-  /**
-   * Skips data events if they are equal to the previous data event.
-   *
-   * The returned stream provides the same events as this stream, except
-   * that it never provides two consecutive data events that are equal.
-   * That is, errors are passed through to the returned stream, and
-   * data events are passed through if they are distinct from the most
-   * recently emitted data event.
-   *
-   * Equality is determined by the provided [equals] method. If that is
-   * omitted, the '==' operator on the last provided data element is used.
-   *
-   * If [equals] throws, the data event is replaced by an error event
-   * containing the thrown error. The behavior is equivalent to the
-   * original stream emitting the error event, and it doesn't change
-   * the what the most recently emitted data event is.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   * If a broadcast stream is listened to more than once, each subscription
-   * will individually perform the `equals` test.
-   */
+  /// Skips data events if they are equal to the previous data event.
+  ///
+  /// The returned stream provides the same events as this stream, except
+  /// that it never provides two consecutive data events that are equal.
+  /// That is, errors are passed through to the returned stream, and
+  /// data events are passed through if they are distinct from the most
+  /// recently emitted data event.
+  ///
+  /// Equality is determined by the provided [equals] method. If that is
+  /// omitted, the '==' operator on the last provided data element is used.
+  ///
+  /// If [equals] throws, the data event is replaced by an error event
+  /// containing the thrown error. The behavior is equivalent to the
+  /// original stream emitting the error event, and it doesn't change
+  /// the what the most recently emitted data event is.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
+  /// If a broadcast stream is listened to more than once, each subscription
+  /// will individually perform the `equals` test.
   Stream<T> distinct([bool equals(T previous, T next)?]) {
     return new _DistinctStream<T>(this, equals);
   }
 
-  /**
-   * The first element of this stream.
-   *
-   * Stops listening to this stream after the first element has been received.
-   *
-   * Internally the method cancels its subscription after the first element.
-   * This means that single-subscription (non-broadcast) streams are closed
-   * and cannot be reused after a call to this getter.
-   *
-   * If an error event occurs before the first data event, the returned future
-   * is completed with that error.
-   *
-   * If this stream is empty (a done event occurs before the first data event),
-   * the returned future completes with an error.
-   *
-   * Except for the type of the error, this method is equivalent to
-   * `this.elementAt(0)`.
-   */
+  /// The first element of this stream.
+  ///
+  /// Stops listening to this stream after the first element has been received.
+  ///
+  /// Internally the method cancels its subscription after the first element.
+  /// This means that single-subscription (non-broadcast) streams are closed
+  /// and cannot be reused after a call to this getter.
+  ///
+  /// If an error event occurs before the first data event, the returned future
+  /// is completed with that error.
+  ///
+  /// If this stream is empty (a done event occurs before the first data event),
+  /// the returned future completes with an error.
+  ///
+  /// Except for the type of the error, this method is equivalent to
+  /// `this.elementAt(0)`.
   Future<T> get first {
     _Future<T> future = new _Future<T>();
     StreamSubscription<T> subscription =
@@ -1304,16 +1221,14 @@
     return future;
   }
 
-  /**
-   * The last element of this stream.
-   *
-   * If this stream emits an error event,
-   * the returned future is completed with that error
-   * and processing stops.
-   *
-   * If this stream is empty (the done event is the first event),
-   * the returned future completes with an error.
-   */
+  /// The last element of this stream.
+  ///
+  /// If this stream emits an error event,
+  /// the returned future is completed with that error
+  /// and processing stops.
+  ///
+  /// If this stream is empty (the done event is the first event),
+  /// the returned future completes with an error.
   Future<T> get last {
     _Future<T> future = new _Future<T>();
     late T result;
@@ -1339,16 +1254,14 @@
     return future;
   }
 
-  /**
-   * The single element of this stream.
-   *
-   * If this stream emits an error event,
-   * the returned future is completed with that error
-   * and processing stops.
-   *
-   * If [this] is empty or has more than one element,
-   * the returned future completes with an error.
-   */
+  /// The single element of this stream.
+  ///
+  /// If this stream emits an error event,
+  /// the returned future is completed with that error
+  /// and processing stops.
+  ///
+  /// If [this] is empty or has more than one element,
+  /// the returned future completes with an error.
   Future<T> get single {
     _Future<T> future = new _Future<T>();
     late T result;
@@ -1381,31 +1294,29 @@
     return future;
   }
 
-  /**
-   * Finds the first element of this stream matching [test].
-   *
-   * Returns a future that is completed with the first element of this stream
-   * that [test] returns `true` for.
-   *
-   * If no such element is found before this stream is done, and a
-   * [orElse] function is provided, the result of calling [orElse]
-   * becomes the value of the future. If [orElse] throws, the returned
-   * future is completed with that error.
-   *
-   * If this stream emits an error before the first matching element,
-   * the returned future is completed with that error, and processing stops.
-   *
-   * Stops listening to this stream after the first matching element or error
-   * has been received.
-   *
-   * Internally the method cancels its subscription after the first element that
-   * matches the predicate. This means that single-subscription (non-broadcast)
-   * streams are closed and cannot be reused after a call to this method.
-   *
-   * If an error occurs, or if this stream ends without finding a match and
-   * with no [orElse] function provided,
-   * the returned future is completed with an error.
-   */
+  /// Finds the first element of this stream matching [test].
+  ///
+  /// Returns a future that is completed with the first element of this stream
+  /// that [test] returns `true` for.
+  ///
+  /// If no such element is found before this stream is done, and a
+  /// [orElse] function is provided, the result of calling [orElse]
+  /// becomes the value of the future. If [orElse] throws, the returned
+  /// future is completed with that error.
+  ///
+  /// If this stream emits an error before the first matching element,
+  /// the returned future is completed with that error, and processing stops.
+  ///
+  /// Stops listening to this stream after the first matching element or error
+  /// has been received.
+  ///
+  /// Internally the method cancels its subscription after the first element that
+  /// matches the predicate. This means that single-subscription (non-broadcast)
+  /// streams are closed and cannot be reused after a call to this method.
+  ///
+  /// If an error occurs, or if this stream ends without finding a match and
+  /// with no [orElse] function provided,
+  /// the returned future is completed with an error.
   Future<T> firstWhere(bool test(T element), {T orElse()?}) {
     _Future<T> future = new _Future();
     StreamSubscription<T> subscription =
@@ -1432,17 +1343,15 @@
     return future;
   }
 
-  /**
-   * Finds the last element in this stream matching [test].
-   *
-   * If this stream emits an error, the returned future is completed with that
-   * error, and processing stops.
-   *
-   * Otherwise as [firstWhere], except that the last matching element is found
-   * instead of the first.
-   * That means that a non-error result cannot be provided before this stream
-   * is done.
-   */
+  /// Finds the last element in this stream matching [test].
+  ///
+  /// If this stream emits an error, the returned future is completed with that
+  /// error, and processing stops.
+  ///
+  /// Otherwise as [firstWhere], except that the last matching element is found
+  /// instead of the first.
+  /// That means that a non-error result cannot be provided before this stream
+  /// is done.
   Future<T> lastWhere(bool test(T element), {T orElse()?}) {
     _Future<T> future = new _Future();
     late T result;
@@ -1475,12 +1384,10 @@
     return future;
   }
 
-  /**
-   * Finds the single element in this stream matching [test].
-   *
-   * Like [lastWhere], except that it is an error if more than one
-   * matching element occurs in this stream.
-   */
+  /// Finds the single element in this stream matching [test].
+  ///
+  /// Like [lastWhere], except that it is an error if more than one
+  /// matching element occurs in this stream.
   Future<T> singleWhere(bool test(T element), {T orElse()?}) {
     _Future<T> future = new _Future<T>();
     late T result;
@@ -1521,22 +1428,20 @@
     return future;
   }
 
-  /**
-   * Returns the value of the [index]th data event of this stream.
-   *
-   * Stops listening to this stream after the [index]th data event has been
-   * received.
-   *
-   * Internally the method cancels its subscription after these elements. This
-   * means that single-subscription (non-broadcast) streams are closed and
-   * cannot be reused after a call to this method.
-   *
-   * If an error event occurs before the value is found, the future completes
-   * with this error.
-   *
-   * If a done event occurs before the value is found, the future completes
-   * with a [RangeError].
-   */
+  /// Returns the value of the [index]th data event of this stream.
+  ///
+  /// Stops listening to this stream after the [index]th data event has been
+  /// received.
+  ///
+  /// Internally the method cancels its subscription after these elements. This
+  /// means that single-subscription (non-broadcast) streams are closed and
+  /// cannot be reused after a call to this method.
+  ///
+  /// If an error event occurs before the value is found, the future completes
+  /// with this error.
+  ///
+  /// If a done event occurs before the value is found, the future completes
+  /// with a [RangeError].
   Future<T> elementAt(int index) {
     RangeError.checkNotNegative(index, "index");
     _Future<T> result = new _Future<T>();
@@ -1559,33 +1464,31 @@
     return result;
   }
 
-  /**
-   * Creates a new stream with the same events as this stream.
-   *
-   * Whenever more than [timeLimit] passes between two events from this stream,
-   * the [onTimeout] function is called, which can emit further events on
-   * the returned stream.
-   *
-   * The countdown doesn't start until the returned stream is listened to.
-   * The countdown is reset every time an event is forwarded from this stream,
-   * or when this stream is paused and resumed.
-   *
-   * The [onTimeout] function is called with one argument: an
-   * [EventSink] that allows putting events into the returned stream.
-   * This `EventSink` is only valid during the call to [onTimeout].
-   * Calling [EventSink.close] on the sink passed to [onTimeout] closes the
-   * returned stream, and no further events are processed.
-   *
-   * If [onTimeout] is omitted, a timeout will just put a [TimeoutException]
-   * into the error channel of the returned stream.
-   * If the call to [onTimeout] throws, the error is emitted on the returned
-   * stream.
-   *
-   * The returned stream is a broadcast stream if this stream is.
-   * If a broadcast stream is listened to more than once, each subscription
-   * will have its individually timer that starts counting on listen,
-   * and the subscriptions' timers can be paused individually.
-   */
+  /// Creates a new stream with the same events as this stream.
+  ///
+  /// Whenever more than [timeLimit] passes between two events from this stream,
+  /// the [onTimeout] function is called, which can emit further events on
+  /// the returned stream.
+  ///
+  /// The countdown doesn't start until the returned stream is listened to.
+  /// The countdown is reset every time an event is forwarded from this stream,
+  /// or when this stream is paused and resumed.
+  ///
+  /// The [onTimeout] function is called with one argument: an
+  /// [EventSink] that allows putting events into the returned stream.
+  /// This `EventSink` is only valid during the call to [onTimeout].
+  /// Calling [EventSink.close] on the sink passed to [onTimeout] closes the
+  /// returned stream, and no further events are processed.
+  ///
+  /// If [onTimeout] is omitted, a timeout will just put a [TimeoutException]
+  /// into the error channel of the returned stream.
+  /// If the call to [onTimeout] throws, the error is emitted on the returned
+  /// stream.
+  ///
+  /// The returned stream is a broadcast stream if this stream is.
+  /// If a broadcast stream is listened to more than once, each subscription
+  /// will have its individually timer that starts counting on listen,
+  /// and the subscriptions' timers can be paused individually.
   Stream<T> timeout(Duration timeLimit, {void onTimeout(EventSink<T> sink)?}) {
     _StreamControllerBase<T> controller;
     if (isBroadcast) {
@@ -1662,198 +1565,169 @@
   }
 }
 
-/**
- * A subscription on events from a [Stream].
- *
- * When you listen on a [Stream] using [Stream.listen],
- * a [StreamSubscription] object is returned.
- *
- * The subscription provides events to the listener,
- * and holds the callbacks used to handle the events.
- * The subscription can also be used to unsubscribe from the events,
- * or to temporarily pause the events from the stream.
- */
+/// A subscription on events from a [Stream].
+///
+/// When you listen on a [Stream] using [Stream.listen],
+/// a [StreamSubscription] object is returned.
+///
+/// The subscription provides events to the listener,
+/// and holds the callbacks used to handle the events.
+/// The subscription can also be used to unsubscribe from the events,
+/// or to temporarily pause the events from the stream.
 abstract class StreamSubscription<T> {
-  /**
-   * Cancels this subscription.
-   *
-   * After this call, the subscription no longer receives events.
-   *
-   * The stream may need to shut down the source of events and clean up after
-   * the subscription is canceled.
-   *
-   * Returns a future that is completed once the stream has finished
-   * its cleanup.
-   *
-   * Typically, cleanup happens when the stream needs to release resources.
-   * For example, a stream might need to close an open file (as an asynchronous
-   * operation). If the listener wants to delete the file after having
-   * canceled the subscription, it must wait for the cleanup future to complete.
-   *
-   * If the cleanup throws, which it really shouldn't, the returned future
-   * completes with that error.
-   */
+  /// Cancels this subscription.
+  ///
+  /// After this call, the subscription no longer receives events.
+  ///
+  /// The stream may need to shut down the source of events and clean up after
+  /// the subscription is canceled.
+  ///
+  /// Returns a future that is completed once the stream has finished
+  /// its cleanup.
+  ///
+  /// Typically, cleanup happens when the stream needs to release resources.
+  /// For example, a stream might need to close an open file (as an asynchronous
+  /// operation). If the listener wants to delete the file after having
+  /// canceled the subscription, it must wait for the cleanup future to complete.
+  ///
+  /// If the cleanup throws, which it really shouldn't, the returned future
+  /// completes with that error.
   Future<void> cancel();
 
-  /**
-   * Replaces the data event handler of this subscription.
-   *
-   * The [handleData] function is called for each element of the stream
-   * after this function is called.
-   * If [handleData] is `null`, further elements are ignored.
-   *
-   * This method replaces the current handler set by the invocation of
-   * [Stream.listen] or by a previous call to [onData].
-   */
+  /// Replaces the data event handler of this subscription.
+  ///
+  /// The [handleData] function is called for each data event of the stream
+  /// after this function is called.
+  /// If [handleData] is `null`, data events are ignored.
+  ///
+  /// This method replaces the current handler set by the invocation of
+  /// [Stream.listen] or by a previous call to [onData].
   void onData(void handleData(T data)?);
 
-  /**
-   * Replaces the error event handler of this subscription.
-   *
-   * The [handleError] function must be able to be called with either
-   * one positional argument, or with two positional arguments
-   * where the seconds is always a [StackTrace].
-   *
-   * The [handleError] argument may be `null`, in which case further
-   * error events are considered unhandled, and will be reported to
-   * [Zone.handleUncaughtError].
-   *
-   * The provided function is called for all error events from the
-   * stream subscription.
-   *
-   * This method replaces the current handler set by the invocation of
-   * [Stream.listen], by calling [asFuture], or by a previous call to [onError].
-   */
+  /// Replaces the error event handler of this subscription.
+  ///
+  /// The [handleError] function must be able to be called with either
+  /// one positional argument, or with two positional arguments
+  /// where the seconds is always a [StackTrace].
+  ///
+  /// The [handleError] argument may be `null`, in which case further
+  /// error events are considered *unhandled*, and will be reported to
+  /// [Zone.handleUncaughtError].
+  ///
+  /// The provided function is called for all error events from the
+  /// stream subscription.
+  ///
+  /// This method replaces the current handler set by the invocation of
+  /// [Stream.listen], by calling [asFuture], or by a previous call to [onError].
   void onError(Function? handleError);
 
-  /**
-   * Replaces the done event handler of this subscription.
-   *
-   * The [handleDone] function is called when the stream closes.
-   * The value may be `null`, in which case no function is called.
-   *
-   * This method replaces the current handler set by the invocation of
-   * [Stream.listen], by calling [asFuture], or by a previous call to [onDone].
-   */
+  /// Replaces the done event handler of this subscription.
+  ///
+  /// The [handleDone] function is called when the stream closes.
+  /// The value may be `null`, in which case no function is called.
+  ///
+  /// This method replaces the current handler set by the invocation of
+  /// [Stream.listen], by calling [asFuture], or by a previous call to [onDone].
   void onDone(void handleDone()?);
 
-  /**
-   * Request that the stream pauses events until further notice.
-   *
-   * While paused, the subscription will not fire any events.
-   * If it receives events from its source, they will be buffered until
-   * the subscription is resumed.
-   * For non-broadcast streams, the underlying source is usually informed
-   * about the pause,
-   * so it can stop generating events until the subscription is resumed.
-   *
-   * To avoid buffering events on a broadcast stream, it is better to
-   * cancel this subscription, and start to listen again when events
-   * are needed, if the intermediate events are not important.
-   *
-   * If [resumeSignal] is provided, the stream subscription will undo the pause
-   * when the future completes, as if by a call to [resume].
-   * If the future completes with an error,
-   * the stream will still resume, but the error will be considered unhandled
-   * and is passed to [Zone.handleUncaughtError].
-   *
-   * A call to [resume] will also undo a pause.
-   *
-   * If the subscription is paused more than once, an equal number
-   * of resumes must be performed to resume the stream.
-   * Calls to [resume] and the completion of a [resumeSignal] are
-   * interchangeable - the [pause] which was passed a [resumeSignal] may be
-   * ended by a call to [resume], and completing the [resumeSignal] may end a
-   * different [pause].
-   *
-   * It is safe to [resume] or complete a [resumeSignal] even when the
-   * subscription is not paused, and the resume will have no effect.
-   *
-   * Currently DOM streams silently drop events when the stream is paused. This
-   * is a bug and will be fixed.
-   */
+  /// Requests that the stream pauses events until further notice.
+  ///
+  /// While paused, the subscription will not fire any events.
+  /// If it receives events from its source, they will be buffered until
+  /// the subscription is resumed.
+  /// For non-broadcast streams, the underlying source is usually informed
+  /// about the pause,
+  /// so it can stop generating events until the subscription is resumed.
+  ///
+  /// To avoid buffering events on a broadcast stream, it is better to
+  /// cancel this subscription, and start to listen again when events
+  /// are needed, if the intermediate events are not important.
+  ///
+  /// If [resumeSignal] is provided, the stream subscription will undo the pause
+  /// when the future completes, as if by a call to [resume].
+  /// If the future completes with an error,
+  /// the stream will still resume, but the error will be considered unhandled
+  /// and is passed to [Zone.handleUncaughtError].
+  ///
+  /// A call to [resume] will also undo a pause.
+  ///
+  /// If the subscription is paused more than once, an equal number
+  /// of resumes must be performed to resume the stream.
+  /// Calls to [resume] and the completion of a [resumeSignal] are
+  /// interchangeable - the [pause] which was passed a [resumeSignal] may be
+  /// ended by a call to [resume], and completing the [resumeSignal] may end a
+  /// different [pause].
+  ///
+  /// It is safe to [resume] or complete a [resumeSignal] even when the
+  /// subscription is not paused, and the resume will have no effect.
   void pause([Future<void>? resumeSignal]);
 
-  /**
-   * Resume after a pause.
-   *
-   * This undoes one previous call to [pause].
-   * When all previously calls to [pause] have been matched by a calls to
-   * [resume], possibly through a `resumeSignal` passed to [pause],
-   * the stream subscription may emit events again.
-   *
-   * It is safe to [resume] even when the subscription is not paused, and the
-   * resume will have no effect.
-   */
+  /// Resumes after a pause.
+  ///
+  /// This undoes one previous call to [pause].
+  /// When all previously calls to [pause] have been matched by a calls to
+  /// [resume], possibly through a `resumeSignal` passed to [pause],
+  /// the stream subscription may emit events again.
+  ///
+  /// It is safe to [resume] even when the subscription is not paused, and the
+  /// resume will have no effect.
   void resume();
 
-  /**
-   * Whether the [StreamSubscription] is currently paused.
-   *
-   * If there have been more calls to [pause] than to [resume] on this
-   * stream subscription, the subscription is paused, and this getter
-   * returns `true`.
-   *
-   * Returns `false` if the stream can currently emit events, or if
-   * the subscription has completed or been cancelled.
-   */
+  /// Whether the [StreamSubscription] is currently paused.
+  ///
+  /// If there have been more calls to [pause] than to [resume] on this
+  /// stream subscription, the subscription is paused, and this getter
+  /// returns `true`.
+  ///
+  /// Returns `false` if the stream can currently emit events, or if
+  /// the subscription has completed or been cancelled.
   bool get isPaused;
 
-  /**
-   * Returns a future that handles the [onDone] and [onError] callbacks.
-   *
-   * This method *overwrites* the existing [onDone] and [onError] callbacks
-   * with new ones that complete the returned future.
-   *
-   * In case of an error the subscription will automatically cancel (even
-   * when it was listening with `cancelOnError` set to `false`).
-   *
-   * In case of a `done` event the future completes with the given
-   * [futureValue].
-   *
-   * If [futureValue] is omitted, the value `null as E` is used as a default.
-   * If `E` is not nullable, this will throw immediately when [asFuture]
-   * is called.
-   */
+  /// Returns a future that handles the [onDone] and [onError] callbacks.
+  ///
+  /// This method *overwrites* the existing [onDone] and [onError] callbacks
+  /// with new ones that complete the returned future.
+  ///
+  /// In case of an error the subscription will automatically cancel (even
+  /// when it was listening with `cancelOnError` set to `false`).
+  ///
+  /// In case of a `done` event the future completes with the given
+  /// [futureValue].
+  ///
+  /// If [futureValue] is omitted, the value `null as E` is used as a default.
+  /// If `E` is not nullable, this will throw immediately when [asFuture]
+  /// is called.
   Future<E> asFuture<E>([E? futureValue]);
 }
 
-/**
- * A [Sink] that supports adding errors.
- *
- * This makes it suitable for capturing the results of asynchronous
- * computations, which can complete with a value or an error.
- *
- * The [EventSink] has been designed to handle asynchronous events from
- * [Stream]s. See, for example, [Stream.eventTransformed] which uses
- * `EventSink`s to transform events.
- */
+/// A [Sink] that supports adding errors.
+///
+/// This makes it suitable for capturing the results of asynchronous
+/// computations, which can complete with a value or an error.
+///
+/// The [EventSink] has been designed to handle asynchronous events from
+/// [Stream]s. See, for example, [Stream.eventTransformed] which uses
+/// `EventSink`s to transform events.
 abstract class EventSink<T> implements Sink<T> {
-  /**
-   * Adds a data [event] to the sink.
-   *
-   * Must not be called on a closed sink.
-   */
+  /// Adds a data [event] to the sink.
+  ///
+  /// Must not be called on a closed sink.
   void add(T event);
 
-  /**
-   * Adds an [error] to the sink.
-   *
-   * Must not be called on a closed sink.
-   */
+  /// Adds an [error] to the sink.
+  ///
+  /// Must not be called on a closed sink.
   void addError(Object error, [StackTrace? stackTrace]);
 
-  /**
-   * Closes the sink.
-   *
-   * Calling this method more than once is allowed, but does nothing.
-   *
-   * Neither [add] nor [addError] must be called after this method.
-   */
+  /// Closes the sink.
+  ///
+  /// Calling this method more than once is allowed, but does nothing.
+  ///
+  /// Neither [add] nor [addError] must be called after this method.
   void close();
 }
 
-/** [Stream] wrapper that only exposes the [Stream] interface. */
+/// [Stream] wrapper that only exposes the [Stream] interface.
 class StreamView<T> extends Stream<T> {
   final Stream<T> _stream;
 
@@ -1875,335 +1749,307 @@
   }
 }
 
-/**
- * Abstract interface for a "sink" accepting multiple entire streams.
- *
- * A consumer can accept a number of consecutive streams using [addStream],
- * and when no further data need to be added, the [close] method tells the
- * consumer to complete its work and shut down.
- *
- * The [Stream.pipe] accepts a `StreamConsumer` and will pass the stream
- * to the consumer's [addStream] method. When that completes, it will
- * call [close] and then complete its own returned future.
- */
+/// Abstract interface for a "sink" accepting multiple entire streams.
+///
+/// A consumer can accept a number of consecutive streams using [addStream],
+/// and when no further data need to be added, the [close] method tells the
+/// consumer to complete its work and shut down.
+///
+/// The [Stream.pipe] accepts a `StreamConsumer` and will pass the stream
+/// to the consumer's [addStream] method. When that completes, it will
+/// call [close] and then complete its own returned future.
 abstract class StreamConsumer<S> {
-  /**
-   * Consumes the elements of [stream].
-   *
-   * Listens on [stream] and does something for each event.
-   *
-   * Returns a future which is completed when the stream is done being added,
-   * and the consumer is ready to accept a new stream.
-   * No further calls to [addStream] or [close] should happen before the
-   * returned future has completed.
-   *
-   * The consumer may stop listening to the stream after an error,
-   * it may consume all the errors and only stop at a done event,
-   * or it may be canceled early if the receiver don't want any further events.
-   *
-   * If the consumer stops listening because of some error preventing it
-   * from continuing, it may report this error in the returned future,
-   * otherwise it will just complete the future with `null`.
-   */
+  /// Consumes the elements of [stream].
+  ///
+  /// Listens on [stream] and does something for each event.
+  ///
+  /// Returns a future which is completed when the stream is done being added,
+  /// and the consumer is ready to accept a new stream.
+  /// No further calls to [addStream] or [close] should happen before the
+  /// returned future has completed.
+  ///
+  /// The consumer may stop listening to the stream after an error,
+  /// it may consume all the errors and only stop at a done event,
+  /// or it may be canceled early if the receiver don't want any further events.
+  ///
+  /// If the consumer stops listening because of some error preventing it
+  /// from continuing, it may report this error in the returned future,
+  /// otherwise it will just complete the future with `null`.
   Future addStream(Stream<S> stream);
 
-  /**
-   * Tells the consumer that no further streams will be added.
-   *
-   * This allows the consumer to complete any remaining work and release
-   * resources that are no longer needed
-   *
-   * Returns a future which is completed when the consumer has shut down.
-   * If cleaning up can fail, the error may be reported in the returned future,
-   * otherwise it completes with `null`.
-   */
+  /// Tells the consumer that no further streams will be added.
+  ///
+  /// This allows the consumer to complete any remaining work and release
+  /// resources that are no longer needed
+  ///
+  /// Returns a future which is completed when the consumer has shut down.
+  /// If cleaning up can fail, the error may be reported in the returned future,
+  /// otherwise it completes with `null`.
   Future close();
 }
 
-/**
- * A object that accepts stream events both synchronously and asynchronously.
- *
- * A [StreamSink] combines the methods from [StreamConsumer] and [EventSink].
- *
- * The [EventSink] methods can't be used while the [addStream] is called.
- * As soon as the [addStream]'s [Future] completes with a value, the
- * [EventSink] methods can be used again.
- *
- * If [addStream] is called after any of the [EventSink] methods, it'll
- * be delayed until the underlying system has consumed the data added by the
- * [EventSink] methods.
- *
- * When [EventSink] methods are used, the [done] [Future] can be used to
- * catch any errors.
- *
- * When [close] is called, it will return the [done] [Future].
- */
+/// A object that accepts stream events both synchronously and asynchronously.
+///
+/// A [StreamSink] combines the methods from [StreamConsumer] and [EventSink].
+///
+/// The [EventSink] methods can't be used while the [addStream] is called.
+/// As soon as the [addStream]'s [Future] completes with a value, the
+/// [EventSink] methods can be used again.
+///
+/// If [addStream] is called after any of the [EventSink] methods, it'll
+/// be delayed until the underlying system has consumed the data added by the
+/// [EventSink] methods.
+///
+/// When [EventSink] methods are used, the [done] [Future] can be used to
+/// catch any errors.
+///
+/// When [close] is called, it will return the [done] [Future].
 abstract class StreamSink<S> implements EventSink<S>, StreamConsumer<S> {
-  /**
-   * Tells the stream sink that no further streams will be added.
-   *
-   * This allows the stream sink to complete any remaining work and release
-   * resources that are no longer needed
-   *
-   * Returns a future which is completed when the stream sink has shut down.
-   * If cleaning up can fail, the error may be reported in the returned future,
-   * otherwise it completes with `null`.
-   *
-   * Returns the same future as [done].
-   *
-   * The stream sink may close before the [close] method is called, either due
-   * to an error or because it is itself providing events to someone who has
-   * stopped listening. In that case, the [done] future is completed first,
-   * and the `close` method will return the `done` future when called.
-   *
-   * Unifies [StreamConsumer.close] and [EventSink.close] which both mark their
-   * object as not expecting any further events.
-   */
+  /// Tells the stream sink that no further streams will be added.
+  ///
+  /// This allows the stream sink to complete any remaining work and release
+  /// resources that are no longer needed
+  ///
+  /// Returns a future which is completed when the stream sink has shut down.
+  /// If cleaning up can fail, the error may be reported in the returned future,
+  /// otherwise it completes with `null`.
+  ///
+  /// Returns the same future as [done].
+  ///
+  /// The stream sink may close before the [close] method is called, either due
+  /// to an error or because it is itself providing events to someone who has
+  /// stopped listening. In that case, the [done] future is completed first,
+  /// and the `close` method will return the `done` future when called.
+  ///
+  /// Unifies [StreamConsumer.close] and [EventSink.close] which both mark their
+  /// object as not expecting any further events.
   Future close();
 
-  /**
-   * Return a future which is completed when the [StreamSink] is finished.
-   *
-   * If the `StreamSink` fails with an error,
-   * perhaps in response to adding events using [add], [addError] or [close],
-   * the [done] future will complete with that error.
-   *
-   * Otherwise, the returned future will complete when either:
-   *
-   * * all events have been processed and the sink has been closed, or
-   * * the sink has otherwise been stopped from handling more events
-   *   (for example by canceling a stream subscription).
-   */
+  /// Return a future which is completed when the [StreamSink] is finished.
+  ///
+  /// If the `StreamSink` fails with an error,
+  /// perhaps in response to adding events using [add], [addError] or [close],
+  /// the [done] future will complete with that error.
+  ///
+  /// Otherwise, the returned future will complete when either:
+  ///
+  /// * all events have been processed and the sink has been closed, or
+  /// * the sink has otherwise been stopped from handling more events
+  ///   (for example by canceling a stream subscription).
   Future get done;
 }
 
-/**
- * Transforms a Stream.
- *
- * When a stream's [Stream.transform] method is invoked with a
- * [StreamTransformer], the stream calls the [bind] method on the provided
- * transformer. The resulting stream is then returned from the
- * [Stream.transform] method.
- *
- * Conceptually, a transformer is simply a function from [Stream] to [Stream]
- * that is encapsulated into a class.
- *
- * It is good practice to write transformers that can be used multiple times.
- *
- * All other transforming methods on [Stream], such as [Stream.map],
- * [Stream.where] or [Stream.expand] can be implemented using
- * [Stream.transform]. A [StreamTransformer] is thus very powerful but often
- * also a bit more complicated to use.
- */
+/// Transforms a Stream.
+///
+/// When a stream's [Stream.transform] method is invoked with a
+/// [StreamTransformer], the stream calls the [bind] method on the provided
+/// transformer. The resulting stream is then returned from the
+/// [Stream.transform] method.
+///
+/// Conceptually, a transformer is simply a function from [Stream] to [Stream]
+/// that is encapsulated into a class.
+///
+/// It is good practice to write transformers that can be used multiple times.
+///
+/// All other transforming methods on [Stream], such as [Stream.map],
+/// [Stream.where] or [Stream.expand] can be implemented using
+/// [Stream.transform]. A [StreamTransformer] is thus very powerful but often
+/// also a bit more complicated to use.
 abstract class StreamTransformer<S, T> {
-  /**
-   * Creates a [StreamTransformer] based on the given [onListen] callback.
-   *
-   * The returned stream transformer uses the provided [onListen] callback
-   * when a transformed stream is listened to. At that time, the callback
-   * receives the input stream (the one passed to [bind]) and a
-   * boolean flag `cancelOnError` to create a [StreamSubscription].
-   *
-   * If the transformed stream is a broadcast stream, so is the stream
-   * returned by the [StreamTransformer.bind] method by this transformer.
-   *
-   * If the transformed stream is listened to multiple times, the [onListen]
-   * callback is called again for each new [Stream.listen] call.
-   * This happens whether the stream is a broadcast stream or not,
-   * but the call will usually fail for non-broadcast streams.
-   *
-   * The [onListen] callback does *not* receive the handlers that were passed
-   * to [Stream.listen]. These are automatically set after the call to the
-   * [onListen] callback (using [StreamSubscription.onData],
-   * [StreamSubscription.onError] and [StreamSubscription.onDone]).
-   *
-   * Most commonly, an [onListen] callback will first call [Stream.listen] on
-   * the provided stream (with the corresponding `cancelOnError` flag), and then
-   * return a new [StreamSubscription].
-   *
-   * There are two common ways to create a StreamSubscription:
-   *
-   * 1. by allocating a [StreamController] and to return the result of
-   *    listening to its stream. It's important to forward pause, resume and
-   *    cancel events (unless the transformer intentionally wants to change
-   *    this behavior).
-   * 2. by creating a new class that implements [StreamSubscription].
-   *    Note that the subscription should run callbacks in the [Zone] the
-   *    stream was listened to (see [Zone] and [Zone.bindCallback]).
-   *
-   * Example:
-   *
-   * ```
-   * /// Starts listening to [input] and duplicates all non-error events.
-   * StreamSubscription<int> _onListen(Stream<int> input, bool cancelOnError) {
-   *   StreamSubscription<String> subscription;
-   *   // Create controller that forwards pause, resume and cancel events.
-   *   var controller = new StreamController<String>(
-   *       onPause: () {
-   *         subscription.pause();
-   *       },
-   *       onResume: () {
-   *         subscription.resume();
-   *       },
-   *       onCancel: () => subscription.cancel(),
-   *       sync: true); // "sync" is correct here, since events are forwarded.
-   *
-   *   // Listen to the provided stream using `cancelOnError`.
-   *   subscription = input.listen((data) {
-   *     // Duplicate the data.
-   *     controller.add(data);
-   *     controller.add(data);
-   *   },
-   *       onError: controller.addError,
-   *       onDone: controller.close,
-   *       cancelOnError: cancelOnError);
-   *
-   *   // Return a new [StreamSubscription] by listening to the controller's
-   *   // stream.
-   *   return controller.stream.listen(null);
-   * }
-   *
-   * // Instantiate a transformer:
-   * var duplicator = const StreamTransformer<int, int>(_onListen);
-   *
-   * // Use as follows:
-   * intStream.transform(duplicator);
-   * ```
-   */
+  /// Creates a [StreamTransformer] based on the given [onListen] callback.
+  ///
+  /// The returned stream transformer uses the provided [onListen] callback
+  /// when a transformed stream is listened to. At that time, the callback
+  /// receives the input stream (the one passed to [bind]) and a
+  /// boolean flag `cancelOnError` to create a [StreamSubscription].
+  ///
+  /// If the transformed stream is a broadcast stream, so is the stream
+  /// returned by the [StreamTransformer.bind] method by this transformer.
+  ///
+  /// If the transformed stream is listened to multiple times, the [onListen]
+  /// callback is called again for each new [Stream.listen] call.
+  /// This happens whether the stream is a broadcast stream or not,
+  /// but the call will usually fail for non-broadcast streams.
+  ///
+  /// The [onListen] callback does *not* receive the handlers that were passed
+  /// to [Stream.listen]. These are automatically set after the call to the
+  /// [onListen] callback (using [StreamSubscription.onData],
+  /// [StreamSubscription.onError] and [StreamSubscription.onDone]).
+  ///
+  /// Most commonly, an [onListen] callback will first call [Stream.listen] on
+  /// the provided stream (with the corresponding `cancelOnError` flag), and then
+  /// return a new [StreamSubscription].
+  ///
+  /// There are two common ways to create a StreamSubscription:
+  ///
+  /// 1. by allocating a [StreamController] and to return the result of
+  ///    listening to its stream. It's important to forward pause, resume and
+  ///    cancel events (unless the transformer intentionally wants to change
+  ///    this behavior).
+  /// 2. by creating a new class that implements [StreamSubscription].
+  ///    Note that the subscription should run callbacks in the [Zone] the
+  ///    stream was listened to (see [Zone] and [Zone.bindCallback]).
+  ///
+  /// Example:
+  ///
+  /// ```
+  /// /// Starts listening to [input] and duplicates all non-error events.
+  /// StreamSubscription<int> _onListen(Stream<int> input, bool cancelOnError) {
+  ///   late StreamSubscription<String> subscription;
+  ///   // Create controller that forwards pause, resume and cancel events.
+  ///   var controller = new StreamController<String>(
+  ///       onPause: () {
+  ///         subscription.pause();
+  ///       },
+  ///       onResume: () {
+  ///         subscription.resume();
+  ///       },
+  ///       onCancel: () => subscription.cancel(),
+  ///       sync: true); // "sync" is correct here, since events are forwarded.
+  ///
+  ///   // Listen to the provided stream.
+  ///   subscription = input.listen((data) {
+  ///     // Duplicate the data.
+  ///     controller.add(data);
+  ///     controller.add(data);
+  ///   },
+  ///       onError: controller.addError,
+  ///       onDone: controller.close,
+  ///       cancelOnError: cancelOnError);
+  ///
+  ///   // Return a new [StreamSubscription] by listening to the controller's
+  ///   // stream.
+  ///   return controller.stream.listen(null);
+  /// }
+  ///
+  /// // Instantiate a transformer:
+  /// var duplicator = const StreamTransformer<int, int>(_onListen);
+  ///
+  /// // Use as follows:
+  /// intStream.transform(duplicator);
+  /// ```
   const factory StreamTransformer(
           StreamSubscription<T> onListen(
               Stream<S> stream, bool cancelOnError)) =
       _StreamSubscriptionTransformer<S, T>;
 
-  /**
-   * Creates a [StreamTransformer] that delegates events to the given functions.
-   *
-   * Example use of a duplicating transformer:
-   *
-   * ```
-   * stringStream.transform(new StreamTransformer<String, String>.fromHandlers(
-   *     handleData: (String value, EventSink<String> sink) {
-   *       sink.add(value);
-   *       sink.add(value);  // Duplicate the incoming events.
-   *     }));
-   * ```
-   *
-   * Transformers that are constructed this way cannot use captured state if
-   * they are used in streams that can be listened to multiple times.
-   * ```
-   * StreamController<String> controller;
-   * controller = new StreamController.broadcast(onListen: () {
-   *   scheduleMicrotask(() {
-   *     controller.addError("Bad");
-   *     controller.addError("Worse");
-   *     controller.addError("Worst");
-   *   });
-   * });
-   * var sharedState = 0;
-   * var transformedStream = controller.stream.transform(
-   *     new StreamTransformer<String>.fromHandlers(
-   *         handleError: (error, stackTrace, sink) {
-   *   sharedState++; // Increment shared error-counter.
-   *   sink.add("Error $sharedState: $error");
-   * }));
-   *
-   * transformedStream.listen(print);
-   * transformedStream.listen(print); // Listen twice.
-   * // Listening twice to the same stream makes the transformer share the same
-   * // state. Instead of having "Error 1: Bad", "Error 2: Worse",
-   * // "Error 3: Worst" as output (each twice for the separate subscriptions),
-   * // this program emits:
-   * // Error 1: Bad
-   * // Error 2: Bad
-   * // Error 3: Worse
-   * // Error 4: Worse
-   * // Error 5: Worst
-   * // Error 6: Worst
-   * ```
-   */
+  /// Creates a [StreamTransformer] that delegates events to the given functions.
+  ///
+  /// Example use of a duplicating transformer:
+  ///
+  /// ```
+  /// stringStream.transform(StreamTransformer<String, String>.fromHandlers(
+  ///     handleData: (String value, EventSink<String> sink) {
+  ///       sink.add(value);
+  ///       sink.add(value);  // Duplicate the incoming events.
+  ///     }));
+  /// ```
+  ///
+  /// Transformers that are constructed this way cannot use captured state if
+  /// they are used in streams that can be listened to multiple times.
+  /// ```
+  /// StreamController<String> controller = StreamController.broadcast()
+  /// controller.onListen = () {
+  ///   scheduleMicrotask(() {
+  ///     controller.addError("Bad");
+  ///     controller.addError("Worse");
+  ///     controller.addError("Worst");
+  ///   });
+  /// };
+  /// var sharedState = 0;
+  /// var transformedStream = controller.stream.transform(
+  ///     StreamTransformer<String>.fromHandlers(
+  ///         handleError: (error, stackTrace, sink) {
+  ///   sharedState++; // Increment shared error-counter.
+  ///   sink.add("Error $sharedState: $error");
+  /// }));
+  ///
+  /// transformedStream.listen(print);
+  /// transformedStream.listen(print); // Listen twice.
+  /// // Listening twice to the same stream makes the transformer share the same
+  /// // state. Instead of having "Error 1: Bad", "Error 2: Worse",
+  /// // "Error 3: Worst" as output (each twice for the separate subscriptions),
+  /// // this program emits:
+  /// // Error 1: Bad
+  /// // Error 2: Bad
+  /// // Error 3: Worse
+  /// // Error 4: Worse
+  /// // Error 5: Worst
+  /// // Error 6: Worst
+  /// ```
   factory StreamTransformer.fromHandlers(
       {void handleData(S data, EventSink<T> sink)?,
       void handleError(Object error, StackTrace stackTrace, EventSink<T> sink)?,
       void handleDone(EventSink<T> sink)?}) = _StreamHandlerTransformer<S, T>;
 
-  /**
-   * Creates a [StreamTransformer] based on a [bind] callback.
-   *
-   * The returned stream transformer uses the [bind] argument to implement the
-   * [StreamTransformer.bind] API and can be used when the transformation is
-   * available as a stream-to-stream function.
-   *
-   * ```dart
-   * final splitDecoded = StreamTransformer<List<int>, String>.fromBind(
-   *     (stream) => stream.transform(utf8.decoder).transform(LineSplitter()));
-   * ```
-   */
+  /// Creates a [StreamTransformer] based on a [bind] callback.
+  ///
+  /// The returned stream transformer uses the [bind] argument to implement the
+  /// [StreamTransformer.bind] API and can be used when the transformation is
+  /// available as a stream-to-stream function.
+  ///
+  /// ```dart
+  /// final splitDecoded = StreamTransformer<List<int>, String>.fromBind(
+  ///     (stream) => stream.transform(utf8.decoder).transform(LineSplitter()));
+  /// ```
   @Since("2.1")
   factory StreamTransformer.fromBind(Stream<T> Function(Stream<S>) bind) =
       _StreamBindTransformer<S, T>;
 
-  /**
-   * Adapts [source] to be a `StreamTransformer<TS, TT>`.
-   *
-   * This allows [source] to be used at the new type, but at run-time it
-   * must satisfy the requirements of both the new type and its original type.
-   *
-   * Data events passed into the returned transformer must also be instances
-   * of [SS], and data events produced by [source] for those events must
-   * also be instances of [TT].
-   */
+  /// Adapts [source] to be a `StreamTransformer<TS, TT>`.
+  ///
+  /// This allows [source] to be used at the new type, but at run-time it
+  /// must satisfy the requirements of both the new type and its original type.
+  ///
+  /// Data events passed into the returned transformer must also be instances
+  /// of [SS], and data events produced by [source] for those events must
+  /// also be instances of [TT].
   static StreamTransformer<TS, TT> castFrom<SS, ST, TS, TT>(
       StreamTransformer<SS, ST> source) {
     return new CastStreamTransformer<SS, ST, TS, TT>(source);
   }
 
-  /**
-   * Transforms the provided [stream].
-   *
-   * Returns a new stream with events that are computed from events of the
-   * provided [stream].
-   *
-   * The [StreamTransformer] interface is completely generic,
-   * so it cannot say what subclasses do.
-   * Each [StreamTransformer] should document clearly how it transforms the
-   * stream (on the class or variable used to access the transformer),
-   * as well as any differences from the following typical behavior:
-   *
-   * * When the returned stream is listened to, it starts listening to the
-   *   input [stream].
-   * * Subscriptions of the returned stream forward (in a reasonable time)
-   *   a [StreamSubscription.pause] call to the subscription of the input
-   *   [stream].
-   * * Similarly, canceling a subscription of the returned stream eventually
-   *   (in reasonable time) cancels the subscription of the input [stream].
-   *
-   * "Reasonable time" depends on the transformer and stream. Some transformers,
-   * like a "timeout" transformer, might make these operations depend on a
-   * duration. Others might not delay them at all, or just by a microtask.
-   *
-   * Transformers are free to handle errors in any way.
-   * A transformer implementation may choose to propagate errors,
-   * or convert them to other events, or ignore them completely,
-   * but if errors are ignored, it should be documented explicitly.
-   */
+  /// Transforms the provided [stream].
+  ///
+  /// Returns a new stream with events that are computed from events of the
+  /// provided [stream].
+  ///
+  /// The [StreamTransformer] interface is completely generic,
+  /// so it cannot say what subclasses do.
+  /// Each [StreamTransformer] should document clearly how it transforms the
+  /// stream (on the class or variable used to access the transformer),
+  /// as well as any differences from the following typical behavior:
+  ///
+  /// * When the returned stream is listened to, it starts listening to the
+  ///   input [stream].
+  /// * Subscriptions of the returned stream forward (in a reasonable time)
+  ///   a [StreamSubscription.pause] call to the subscription of the input
+  ///   [stream].
+  /// * Similarly, canceling a subscription of the returned stream eventually
+  ///   (in reasonable time) cancels the subscription of the input [stream].
+  ///
+  /// "Reasonable time" depends on the transformer and stream. Some transformers,
+  /// like a "timeout" transformer, might make these operations depend on a
+  /// duration. Others might not delay them at all, or just by a microtask.
+  ///
+  /// Transformers are free to handle errors in any way.
+  /// A transformer implementation may choose to propagate errors,
+  /// or convert them to other events, or ignore them completely,
+  /// but if errors are ignored, it should be documented explicitly.
   Stream<T> bind(Stream<S> stream);
 
-  /**
-   * Provides a `StreamTransformer<RS, RT>` view of this stream transformer.
-   *
-   * The resulting transformer will check at run-time that all data events
-   * of the stream it transforms are actually instances of [S],
-   * and it will check that all data events produced by this transformer
-   * are actually instances of [RT].
-   */
+  /// Provides a `StreamTransformer<RS, RT>` view of this stream transformer.
+  ///
+  /// The resulting transformer will check at run-time that all data events
+  /// of the stream it transforms are actually instances of [S],
+  /// and it will check that all data events produced by this transformer
+  /// are actually instances of [RT].
   StreamTransformer<RS, RT> cast<RS, RT>();
 }
 
-/**
- * Base class for implementing [StreamTransformer].
- *
- * Contains default implementations of every method except [bind].
- */
+/// Base class for implementing [StreamTransformer].
+///
+/// Contains default implementations of every method except [bind].
 abstract class StreamTransformerBase<S, T> implements StreamTransformer<S, T> {
   const StreamTransformerBase();
 
@@ -2211,80 +2057,71 @@
       StreamTransformer.castFrom<S, T, RS, RT>(this);
 }
 
-/**
- * An [Iterator]-like interface for the values of a [Stream].
- *
- * This wraps a [Stream] and a subscription on the stream. It listens
- * on the stream, and completes the future returned by [moveNext] when the
- * next value becomes available.
- *
- * The stream may be paused between calls to [moveNext].
- *
- * The [current] value must only be used after a future returned by [moveNext]
- * has completed with `true`, and only until [moveNext] is called again.
- */
+/// An [Iterator]-like interface for the values of a [Stream].
+///
+/// This wraps a [Stream] and a subscription on the stream. It listens
+/// on the stream, and completes the future returned by [moveNext] when the
+/// next value becomes available.
+///
+/// The stream may be paused between calls to [moveNext].
+///
+/// The [current] value must only be used after a future returned by [moveNext]
+/// has completed with `true`, and only until [moveNext] is called again.
 abstract class StreamIterator<T> {
-  /** Create a [StreamIterator] on [stream]. */
+  /// Create a [StreamIterator] on [stream].
   factory StreamIterator(Stream<T> stream) =>
       // TODO(lrn): use redirecting factory constructor when type
       // arguments are supported.
       new _StreamIterator<T>(stream);
 
-  /**
-   * Wait for the next stream value to be available.
-   *
-   * Returns a future which will complete with either `true` or `false`.
-   * Completing with `true` means that another event has been received and
-   * can be read as [current].
-   * Completing with `false` means that the stream iteration is done and
-   * no further events will ever be available.
-   * The future may complete with an error, if the stream produces an error,
-   * which also ends iteration.
-   *
-   * The function must not be called again until the future returned by a
-   * previous call is completed.
-   */
+  /// Wait for the next stream value to be available.
+  ///
+  /// Returns a future which will complete with either `true` or `false`.
+  /// Completing with `true` means that another event has been received and
+  /// can be read as [current].
+  /// Completing with `false` means that the stream iteration is done and
+  /// no further events will ever be available.
+  /// The future may complete with an error, if the stream produces an error,
+  /// which also ends iteration.
+  ///
+  /// The function must not be called again until the future returned by a
+  /// previous call is completed.
   Future<bool> moveNext();
 
-  /**
-   * The current value of the stream.
-   *
-   * When a [moveNext] call completes with `true`, the [current] field holds
-   * the most recent event of the stream, and it stays like that until the next
-   * call to [moveNext]. This value must only be read after a call to [moveNext]
-   * has completed with `true`, and only until the [moveNext] is called again.
-   *
-   * If the StreamIterator has not yet been moved to the first element
-   * ([moveNext] has not been called and completed yet), or if the
-   * StreamIterator has been moved past the last element ([moveNext] has
-   * returned `false`), then [current] is unspecified. A [StreamIterator] may
-   * either throw or return an iterator-specific default value in that case.
-   */
+  /// The current value of the stream.
+  ///
+  /// When a [moveNext] call completes with `true`, the [current] field holds
+  /// the most recent event of the stream, and it stays like that until the next
+  /// call to [moveNext]. This value must only be read after a call to [moveNext]
+  /// has completed with `true`, and only until the [moveNext] is called again.
+  ///
+  /// If the StreamIterator has not yet been moved to the first element
+  /// ([moveNext] has not been called and completed yet), or if the
+  /// StreamIterator has been moved past the last element ([moveNext] has
+  /// returned `false`), then [current] is unspecified. A [StreamIterator] may
+  /// either throw or return an iterator-specific default value in that case.
   T get current;
 
-  /**
-   * Cancels the stream iterator (and the underlying stream subscription) early.
-   *
-   * The stream iterator is automatically canceled if the [moveNext] future
-   * completes with either `false` or an error.
-   *
-   * If you need to stop listening for values before the stream iterator is
-   * automatically closed, you must call [cancel] to ensure that the stream
-   * is properly closed.
-   *
-   * If [moveNext] has been called when the iterator is canceled,
-   * its returned future will complete with `false` as value,
-   * as will all further calls to [moveNext].
-   *
-   * Returns a future if the cancel-operation is not completed synchronously.
-   * Otherwise returns `null`.
-   */
+  /// Cancels the stream iterator (and the underlying stream subscription) early.
+  ///
+  /// The stream iterator is automatically canceled if the [moveNext] future
+  /// completes with either `false` or an error.
+  ///
+  /// If you need to stop listening for values before the stream iterator is
+  /// automatically closed, you must call [cancel] to ensure that the stream
+  /// is properly closed.
+  ///
+  /// If [moveNext] has been called when the iterator is canceled,
+  /// its returned future will complete with `false` as value,
+  /// as will all further calls to [moveNext].
+  ///
+  /// Returns a future which completes when the cancellation is complete.
+  /// This can be an already completed future if the cancellation happens
+  /// synchronously.
   Future cancel();
 }
 
-/**
- * Wraps an [_EventSink] so it exposes only the [EventSink] interface.
- */
+/// Wraps an [_EventSink] so it exposes only the [EventSink] interface.
 class _ControllerEventSinkWrapper<T> implements EventSink<T> {
   EventSink? _sink;
   _ControllerEventSinkWrapper(this._sink);
@@ -2308,50 +2145,42 @@
   }
 }
 
-/**
- * An enhanced stream controller provided by [Stream.multi].
- *
- * Acts like a normal asynchronous controller, but also allows
- * adding events synchronously.
- * As with any synchronous event delivery, the sender should be very careful
- * to not deliver events at times when a new listener might not
- * be ready to receive them.
- * That generally means only delivering events synchronously in response to other
- * asynchronous events, because that is a time when an asynchronous event could
- * happen.
- */
+/// An enhanced stream controller provided by [Stream.multi].
+///
+/// Acts like a normal asynchronous controller, but also allows
+/// adding events synchronously.
+/// As with any synchronous event delivery, the sender should be very careful
+/// to not deliver events at times when a new listener might not
+/// be ready to receive them.
+/// That generally means only delivering events synchronously in response to other
+/// asynchronous events, because that is a time when an asynchronous event could
+/// happen.
 @Since("2.9")
 abstract class MultiStreamController<T> implements StreamController<T> {
-  /**
-   * Adds and delivers an event.
-   *
-   * Adds an event like [add] and attempts to deliver it immediately.
-   * Delivery can be delayed if other previously added events are
-   * still pending delivery, if the subscription is paused,
-   * or if the subscription isn't listening yet.
-   */
+  /// Adds and delivers an event.
+  ///
+  /// Adds an event like [add] and attempts to deliver it immediately.
+  /// Delivery can be delayed if other previously added events are
+  /// still pending delivery, if the subscription is paused,
+  /// or if the subscription isn't listening yet.
   void addSync(T value);
 
-  /**
-   * Adds and delivers an error event.
-   *
-   * Adds an error like [addError] and attempts to deliver it immediately.
-   * Delivery can be delayed if other previously added events are
-   * still pending delivery, if the subscription is paused,
-   * or if the subscription isn't listening yet.
-   */
+  /// Adds and delivers an error event.
+  ///
+  /// Adds an error like [addError] and attempts to deliver it immediately.
+  /// Delivery can be delayed if other previously added events are
+  /// still pending delivery, if the subscription is paused,
+  /// or if the subscription isn't listening yet.
   void addErrorSync(Object error, [StackTrace? stackTrace]);
 
-  /**
-   * Closes the controller and delivers a done event.
-   *
-   * Closes the controller like [close] and attempts to deliver a "done"
-   * event immediately.
-   * Delivery can be delayed if other previously added events are
-   * still pending delivery, if the subscription is paused,
-   * or if the subscription isn't listening yet.
-   * If it's necessary to know whether the "done" event has been delievered,
-   * [done] future will complete when that has happened.
-   */
+  /// Closes the controller and delivers a done event.
+  ///
+  /// Closes the controller like [close] and attempts to deliver a "done"
+  /// event immediately.
+  /// Delivery can be delayed if other previously added events are
+  /// still pending delivery, if the subscription is paused,
+  /// or if the subscription isn't listening yet.
+  /// If it's necessary to know whether the "done" event has been delievered,
+  /// [done] future will complete when that has happened.
   void closeSync();
 }
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index dbaacc1..981cfb2 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -8,71 +8,63 @@
 // Controller for creating and adding events to a stream.
 // -------------------------------------------------------------------
 
-/**
- * Type of a stream controller's `onListen`, `onPause` and `onResume` callbacks.
- */
+/// Type of a stream controller's `onListen`, `onPause` and `onResume` callbacks.
 typedef void ControllerCallback();
 
-/**
- * Type of stream controller `onCancel` callbacks.
- */
+/// Type of stream controller `onCancel` callbacks.
 typedef FutureOr<void> ControllerCancelCallback();
 
-/**
- * A controller with the stream it controls.
- *
- * This controller allows sending data, error and done events on
- * its [stream].
- * This class can be used to create a simple stream that others
- * can listen on, and to push events to that stream.
- *
- * It's possible to check whether the stream is paused or not, and whether
- * it has subscribers or not, as well as getting a callback when either of
- * these change.
- */
+/// A controller with the stream it controls.
+///
+/// This controller allows sending data, error and done events on
+/// its [stream].
+/// This class can be used to create a simple stream that others
+/// can listen on, and to push events to that stream.
+///
+/// It's possible to check whether the stream is paused or not, and whether
+/// it has subscribers or not, as well as getting a callback when either of
+/// these change.
 abstract class StreamController<T> implements StreamSink<T> {
-  /** The stream that this controller is controlling. */
+  /// The stream that this controller is controlling.
   Stream<T> get stream;
 
-  /**
-   * A controller with a [stream] that supports only one single subscriber.
-   *
-   * If [sync] is true, the returned stream controller is a
-   * [SynchronousStreamController], and must be used with the care
-   * and attention necessary to not break the [Stream] contract. If in doubt,
-   * use the non-sync version.
-   *
-   * Using an asynchronous controller will never give the wrong
-   * behavior, but using a synchronous controller incorrectly can cause
-   * otherwise correct programs to break.
-   *
-   * A synchronous controller is only intended for optimizing event
-   * propagation when one asynchronous event immediately triggers another.
-   * It should not be used unless the calls to [add] or [addError]
-   * are guaranteed to occur in places where it won't break `Stream` invariants.
-   *
-   * Use synchronous controllers only to forward (potentially transformed)
-   * events from another stream or a future.
-   *
-   * A Stream should be inert until a subscriber starts listening on it (using
-   * the [onListen] callback to start producing events). Streams should not
-   * leak resources (like websockets) when no user ever listens on the stream.
-   *
-   * The controller buffers all incoming events until a subscriber is
-   * registered, but this feature should only be used in rare circumstances.
-   *
-   * The [onPause] function is called when the stream becomes
-   * paused. [onResume] is called when the stream resumed.
-   *
-   * The [onListen] callback is called when the stream
-   * receives its listener and [onCancel] when the listener ends
-   * its subscription. If [onCancel] needs to perform an asynchronous operation,
-   * [onCancel] should return a future that completes when the cancel operation
-   * is done.
-   *
-   * If the stream is canceled before the controller needs data the
-   * [onResume] call might not be executed.
-   */
+  /// A controller with a [stream] that supports only one single subscriber.
+  ///
+  /// If [sync] is true, the returned stream controller is a
+  /// [SynchronousStreamController], and must be used with the care
+  /// and attention necessary to not break the [Stream] contract. If in doubt,
+  /// use the non-sync version.
+  ///
+  /// Using an asynchronous controller will never give the wrong
+  /// behavior, but using a synchronous controller incorrectly can cause
+  /// otherwise correct programs to break.
+  ///
+  /// A synchronous controller is only intended for optimizing event
+  /// propagation when one asynchronous event immediately triggers another.
+  /// It should not be used unless the calls to [add] or [addError]
+  /// are guaranteed to occur in places where it won't break `Stream` invariants.
+  ///
+  /// Use synchronous controllers only to forward (potentially transformed)
+  /// events from another stream or a future.
+  ///
+  /// A Stream should be inert until a subscriber starts listening on it (using
+  /// the [onListen] callback to start producing events). Streams should not
+  /// leak resources (like websockets) when no user ever listens on the stream.
+  ///
+  /// The controller buffers all incoming events until a subscriber is
+  /// registered, but this feature should only be used in rare circumstances.
+  ///
+  /// The [onPause] function is called when the stream becomes
+  /// paused. [onResume] is called when the stream resumed.
+  ///
+  /// The [onListen] callback is called when the stream
+  /// receives its listener and [onCancel] when the listener ends
+  /// its subscription. If [onCancel] needs to perform an asynchronous operation,
+  /// [onCancel] should return a future that completes when the cancel operation
+  /// is done.
+  ///
+  /// If the stream is canceled before the controller needs data the
+  /// [onResume] call might not be executed.
   factory StreamController(
       {void onListen()?,
       void onPause()?,
@@ -84,57 +76,55 @@
         : _AsyncStreamController<T>(onListen, onPause, onResume, onCancel);
   }
 
-  /**
-   * A controller where [stream] can be listened to more than once.
-   *
-   * The [Stream] returned by [stream] is a broadcast stream.
-   * It can be listened to more than once.
-   *
-   * A Stream should be inert until a subscriber starts listening on it (using
-   * the [onListen] callback to start producing events). Streams should not
-   * leak resources (like websockets) when no user ever listens on the stream.
-   *
-   * Broadcast streams do not buffer events when there is no listener.
-   *
-   * The controller distributes any events to all currently subscribed
-   * listeners at the time when [add], [addError] or [close] is called.
-   * It is not allowed to call `add`, `addError`, or `close` before a previous
-   * call has returned. The controller does not have any internal queue of
-   * events, and if there are no listeners at the time the event is added,
-   * it will just be dropped, or, if it is an error, be reported as uncaught.
-   *
-   * Each listener subscription is handled independently,
-   * and if one pauses, only the pausing listener is affected.
-   * A paused listener will buffer events internally until unpaused or canceled.
-   *
-   * If [sync] is true, events may be fired directly by the stream's
-   * subscriptions during an [add], [addError] or [close] call.
-   * The returned stream controller is a [SynchronousStreamController],
-   * and must be used with the care and attention necessary to not break
-   * the [Stream] contract.
-   * See [Completer.sync] for some explanations on when a synchronous
-   * dispatching can be used.
-   * If in doubt, keep the controller non-sync.
-   *
-   * If [sync] is false, the event will always be fired at a later time,
-   * after the code adding the event has completed.
-   * In that case, no guarantees are given with regard to when
-   * multiple listeners get the events, except that each listener will get
-   * all events in the correct order. Each subscription handles the events
-   * individually.
-   * If two events are sent on an async controller with two listeners,
-   * one of the listeners may get both events
-   * before the other listener gets any.
-   * A listener must be subscribed both when the event is initiated
-   * (that is, when [add] is called)
-   * and when the event is later delivered,
-   * in order to receive the event.
-   *
-   * The [onListen] callback is called when the first listener is subscribed,
-   * and the [onCancel] is called when there are no longer any active listeners.
-   * If a listener is added again later, after the [onCancel] was called,
-   * the [onListen] will be called again.
-   */
+  /// A controller where [stream] can be listened to more than once.
+  ///
+  /// The [Stream] returned by [stream] is a broadcast stream.
+  /// It can be listened to more than once.
+  ///
+  /// A Stream should be inert until a subscriber starts listening on it (using
+  /// the [onListen] callback to start producing events). Streams should not
+  /// leak resources (like websockets) when no user ever listens on the stream.
+  ///
+  /// Broadcast streams do not buffer events when there is no listener.
+  ///
+  /// The controller distributes any events to all currently subscribed
+  /// listeners at the time when [add], [addError] or [close] is called.
+  /// It is not allowed to call `add`, `addError`, or `close` before a previous
+  /// call has returned. The controller does not have any internal queue of
+  /// events, and if there are no listeners at the time the event is added,
+  /// it will just be dropped, or, if it is an error, be reported as uncaught.
+  ///
+  /// Each listener subscription is handled independently,
+  /// and if one pauses, only the pausing listener is affected.
+  /// A paused listener will buffer events internally until unpaused or canceled.
+  ///
+  /// If [sync] is true, events may be fired directly by the stream's
+  /// subscriptions during an [add], [addError] or [close] call.
+  /// The returned stream controller is a [SynchronousStreamController],
+  /// and must be used with the care and attention necessary to not break
+  /// the [Stream] contract.
+  /// See [Completer.sync] for some explanations on when a synchronous
+  /// dispatching can be used.
+  /// If in doubt, keep the controller non-sync.
+  ///
+  /// If [sync] is false, the event will always be fired at a later time,
+  /// after the code adding the event has completed.
+  /// In that case, no guarantees are given with regard to when
+  /// multiple listeners get the events, except that each listener will get
+  /// all events in the correct order. Each subscription handles the events
+  /// individually.
+  /// If two events are sent on an async controller with two listeners,
+  /// one of the listeners may get both events
+  /// before the other listener gets any.
+  /// A listener must be subscribed both when the event is initiated
+  /// (that is, when [add] is called)
+  /// and when the event is later delivered,
+  /// in order to receive the event.
+  ///
+  /// The [onListen] callback is called when the first listener is subscribed,
+  /// and the [onCancel] is called when there are no longer any active listeners.
+  /// If a listener is added again later, after the [onCancel] was called,
+  /// the [onListen] will be called again.
   factory StreamController.broadcast(
       {void onListen()?, void onCancel()?, bool sync = false}) {
     return sync
@@ -142,259 +132,219 @@
         : _AsyncBroadcastStreamController<T>(onListen, onCancel);
   }
 
-  /**
-   * The callback which is called when the stream is listened to.
-   *
-   * May be set to `null`, in which case no callback will happen.
-   */
-  void Function()? get onListen;
+  /// The callback which is called when the stream is listened to.
+  ///
+  /// May be set to `null`, in which case no callback will happen.
+  abstract void Function()? onListen;
 
-  void set onListen(void onListenHandler()?);
+  /// The callback which is called when the stream is paused.
+  ///
+  /// May be set to `null`, in which case no callback will happen.
+  ///
+  /// Pause related callbacks are not supported on broadcast stream controllers.
+  abstract void Function()? onPause;
 
-  /**
-   * The callback which is called when the stream is paused.
-   *
-   * May be set to `null`, in which case no callback will happen.
-   *
-   * Pause related callbacks are not supported on broadcast stream controllers.
-   */
-  void Function()? get onPause;
+  /// The callback which is called when the stream is resumed.
+  ///
+  /// May be set to `null`, in which case no callback will happen.
+  ///
+  /// Pause related callbacks are not supported on broadcast stream controllers.
+  abstract void Function()? onResume;
 
-  void set onPause(void onPauseHandler()?);
+  /// The callback which is called when the stream is canceled.
+  ///
+  /// May be set to `null`, in which case no callback will happen.
+  abstract FutureOr<void> Function()? onCancel;
 
-  /**
-   * The callback which is called when the stream is resumed.
-   *
-   * May be set to `null`, in which case no callback will happen.
-   *
-   * Pause related callbacks are not supported on broadcast stream controllers.
-   */
-  void Function()? get onResume;
-
-  void set onResume(void onResumeHandler()?);
-
-  /**
-   * The callback which is called when the stream is canceled.
-   *
-   * May be set to `null`, in which case no callback will happen.
-   */
-  FutureOr<void> Function()? get onCancel;
-
-  void set onCancel(FutureOr<void> onCancelHandler()?);
-
-  /**
-   * Returns a view of this object that only exposes the [StreamSink] interface.
-   */
+  /// Returns a view of this object that only exposes the [StreamSink] interface.
   StreamSink<T> get sink;
 
-  /**
-   * Whether the stream controller is closed for adding more events.
-   *
-   * The controller becomes closed by calling the [close] method.
-   * New events cannot be added, by calling [add] or [addError],
-   * to a closed controller.
-   *
-   * If the controller is closed,
-   * the "done" event might not have been delivered yet,
-   * but it has been scheduled, and it is too late to add more events.
-   */
+  /// Whether the stream controller is closed for adding more events.
+  ///
+  /// The controller becomes closed by calling the [close] method.
+  /// New events cannot be added, by calling [add] or [addError],
+  /// to a closed controller.
+  ///
+  /// If the controller is closed,
+  /// the "done" event might not have been delivered yet,
+  /// but it has been scheduled, and it is too late to add more events.
   bool get isClosed;
 
-  /**
-   * Whether the subscription would need to buffer events.
-   *
-   * This is the case if the controller's stream has a listener and it is
-   * paused, or if it has not received a listener yet. In that case, the
-   * controller is considered paused as well.
-   *
-   * A broadcast stream controller is never considered paused. It always
-   * forwards its events to all uncanceled subscriptions, if any,
-   * and let the subscriptions handle their own pausing and buffering.
-   */
+  /// Whether the subscription would need to buffer events.
+  ///
+  /// This is the case if the controller's stream has a listener and it is
+  /// paused, or if it has not received a listener yet. In that case, the
+  /// controller is considered paused as well.
+  ///
+  /// A broadcast stream controller is never considered paused. It always
+  /// forwards its events to all uncanceled subscriptions, if any,
+  /// and let the subscriptions handle their own pausing and buffering.
   bool get isPaused;
 
-  /** Whether there is a subscriber on the [Stream]. */
+  /// Whether there is a subscriber on the [Stream].
   bool get hasListener;
 
-  /**
-   * Sends a data [event].
-   *
-   * Listeners receive this event in a later microtask.
-   *
-   * Note that a synchronous controller (created by passing true to the `sync`
-   * parameter of the `StreamController` constructor) delivers events
-   * immediately. Since this behavior violates the contract mentioned here,
-   * synchronous controllers should only be used as described in the
-   * documentation to ensure that the delivered events always *appear* as if
-   * they were delivered in a separate microtask.
-   */
+  /// Sends a data [event].
+  ///
+  /// Listeners receive this event in a later microtask.
+  ///
+  /// Note that a synchronous controller (created by passing true to the `sync`
+  /// parameter of the `StreamController` constructor) delivers events
+  /// immediately. Since this behavior violates the contract mentioned here,
+  /// synchronous controllers should only be used as described in the
+  /// documentation to ensure that the delivered events always *appear* as if
+  /// they were delivered in a separate microtask.
   void add(T event);
 
-  /**
-   * Sends or enqueues an error event.
-   *
-   * If [error] is `null`, it is replaced by a [NullThrownError].
-   *
-   * Listeners receive this event at a later microtask. This behavior can be
-   * overridden by using `sync` controllers. Note, however, that sync
-   * controllers have to satisfy the preconditions mentioned in the
-   * documentation of the constructors.
-   */
+  /// Sends or enqueues an error event.
+  ///
+  /// If [error] is `null`, it is replaced by a [NullThrownError].
+  ///
+  /// Listeners receive this event at a later microtask. This behavior can be
+  /// overridden by using `sync` controllers. Note, however, that sync
+  /// controllers have to satisfy the preconditions mentioned in the
+  /// documentation of the constructors.
   void addError(Object error, [StackTrace? stackTrace]);
 
-  /**
-   * Closes the stream.
-   *
-   * No further events can be added to a closed stream.
-   *
-   * The returned future is the same future provided by [done].
-   * It is completed when the stream listeners is done sending events,
-   * This happens either when the done event has been sent,
-   * or when the subscriber on a single-subscription stream is canceled.
-   *
-   * A broadcast stream controller will send the done event
-   * even if listeners are paused, so some broadcast events may not have been
-   * received yet when the returned future completes.
-   *
-   * If noone listens to a non-broadcast stream,
-   * or the listener pauses and never resumes,
-   * the done event will not be sent and this future will never complete.
-   */
+  /// Closes the stream.
+  ///
+  /// No further events can be added to a closed stream.
+  ///
+  /// The returned future is the same future provided by [done].
+  /// It is completed when the stream listeners is done sending events,
+  /// This happens either when the done event has been sent,
+  /// or when the subscriber on a single-subscription stream is canceled.
+  ///
+  /// A broadcast stream controller will send the done event
+  /// even if listeners are paused, so some broadcast events may not have been
+  /// received yet when the returned future completes.
+  ///
+  /// If noone listens to a non-broadcast stream,
+  /// or the listener pauses and never resumes,
+  /// the done event will not be sent and this future will never complete.
   Future close();
 
-  /**
-   * A future which is completed when the stream controller is done
-   * sending events.
-   *
-   * This happens either when the done event has been sent, or if the
-   * subscriber on a single-subscription stream is canceled.
-   *
-   * A broadcast stream controller will send the done event
-   * even if listeners are paused, so some broadcast events may not have been
-   * received yet when the returned future completes.
-   *
-   * If there is no listener on a non-broadcast stream,
-   * or the listener pauses and never resumes,
-   * the done event will not be sent and this future will never complete.
-   */
+  /// A future which is completed when the stream controller is done
+  /// sending events.
+  ///
+  /// This happens either when the done event has been sent, or if the
+  /// subscriber on a single-subscription stream is canceled.
+  ///
+  /// A broadcast stream controller will send the done event
+  /// even if listeners are paused, so some broadcast events may not have been
+  /// received yet when the returned future completes.
+  ///
+  /// If there is no listener on a non-broadcast stream,
+  /// or the listener pauses and never resumes,
+  /// the done event will not be sent and this future will never complete.
   Future get done;
 
-  /**
-   * Receives events from [source] and puts them into this controller's stream.
-   *
-   * Returns a future which completes when the source stream is done.
-   *
-   * Events must not be added directly to this controller using [add],
-   * [addError], [close] or [addStream], until the returned future
-   * is complete.
-   *
-   * Data and error events are forwarded to this controller's stream. A done
-   * event on the source will end the `addStream` operation and complete the
-   * returned future.
-   *
-   * If [cancelOnError] is true, only the first error on [source] is
-   * forwarded to the controller's stream, and the `addStream` ends
-   * after this. If [cancelOnError] is false, all errors are forwarded
-   * and only a done event will end the `addStream`.
-   * If [cancelOnError] is omitted or `null`, it defaults to false.
-   */
+  /// Receives events from [source] and puts them into this controller's stream.
+  ///
+  /// Returns a future which completes when the source stream is done.
+  ///
+  /// Events must not be added directly to this controller using [add],
+  /// [addError], [close] or [addStream], until the returned future
+  /// is complete.
+  ///
+  /// Data and error events are forwarded to this controller's stream. A done
+  /// event on the source will end the `addStream` operation and complete the
+  /// returned future.
+  ///
+  /// If [cancelOnError] is `true`, only the first error on [source] is
+  /// forwarded to the controller's stream, and the `addStream` ends
+  /// after this. If [cancelOnError] is false, all errors are forwarded
+  /// and only a done event will end the `addStream`.
+  /// If [cancelOnError] is omitted or `null`, it defaults to `false`.
   Future addStream(Stream<T> source, {bool? cancelOnError});
 }
 
-/**
- * A stream controller that delivers its events synchronously.
- *
- * A synchronous stream controller is intended for cases where
- * an already asynchronous event triggers an event on a stream.
- *
- * Instead of adding the event to the stream in a later microtask,
- * causing extra latency, the event is instead fired immediately by the
- * synchronous stream controller, as if the stream event was
- * the current event or microtask.
- *
- * The synchronous stream controller can be used to break the contract
- * on [Stream], and it must be used carefully to avoid doing so.
- *
- * The only advantage to using a [SynchronousStreamController] over a
- * normal [StreamController] is the improved latency.
- * Only use the synchronous version if the improvement is significant,
- * and if its use is safe. Otherwise just use a normal stream controller,
- * which will always have the correct behavior for a [Stream], and won't
- * accidentally break other code.
- *
- * Adding events to a synchronous controller should only happen as the
- * very last part of the handling of the original event.
- * At that point, adding an event to the stream is equivalent to
- * returning to the event loop and adding the event in the next microtask.
- *
- * Each listener callback will be run as if it was a top-level event
- * or microtask. This means that if it throws, the error will be reported as
- * uncaught as soon as possible.
- * This is one reason to add the event as the last thing in the original event
- * handler - any action done after adding the event will delay the report of
- * errors in the event listener callbacks.
- *
- * If an event is added in a setting that isn't known to be another event,
- * it may cause the stream's listener to get that event before the listener
- * is ready to handle it. We promise that after calling [Stream.listen],
- * you won't get any events until the code doing the listen has completed.
- * Calling [add] in response to a function call of unknown origin may break
- * that promise.
- *
- * An [onListen] callback from the controller is *not* an asynchronous event,
- * and adding events to the controller in the `onListen` callback is always
- * wrong. The events will be delivered before the listener has even received
- * the subscription yet.
- *
- * The synchronous broadcast stream controller also has a restrictions that a
- * normal stream controller does not:
- * The [add], [addError], [close] and [addStream] methods *must not* be
- * called while an event is being delivered.
- * That is, if a callback on a subscription on the controller's stream causes
- * a call to any of the functions above, the call will fail.
- * A broadcast stream may have more than one listener, and if an
- * event is added synchronously while another is being also in the process
- * of being added, the latter event might reach some listeners before
- * the former. To prevent that, an event cannot be added while a previous
- * event is being fired.
- * This guarantees that an event is fully delivered when the
- * first [add], [addError] or [close] returns,
- * and further events will be delivered in the correct order.
- *
- * This still only guarantees that the event is delivered to the subscription.
- * If the subscription is paused, the actual callback may still happen later,
- * and the event will instead be buffered by the subscription.
- * Barring pausing, and the following buffered events that haven't been
- * delivered yet, callbacks will be called synchronously when an event is added.
- *
- * Adding an event to a synchronous non-broadcast stream controller while
- * another event is in progress may cause the second event to be delayed
- * and not be delivered synchronously, and until that event is delivered,
- * the controller will not act synchronously.
- */
+/// A stream controller that delivers its events synchronously.
+///
+/// A synchronous stream controller is intended for cases where
+/// an already asynchronous event triggers an event on a stream.
+///
+/// Instead of adding the event to the stream in a later microtask,
+/// causing extra latency, the event is instead fired immediately by the
+/// synchronous stream controller, as if the stream event was
+/// the current event or microtask.
+///
+/// The synchronous stream controller can be used to break the contract
+/// on [Stream], and it must be used carefully to avoid doing so.
+///
+/// The only advantage to using a [SynchronousStreamController] over a
+/// normal [StreamController] is the improved latency.
+/// Only use the synchronous version if the improvement is significant,
+/// and if its use is safe. Otherwise just use a normal stream controller,
+/// which will always have the correct behavior for a [Stream], and won't
+/// accidentally break other code.
+///
+/// Adding events to a synchronous controller should only happen as the
+/// very last part of the handling of the original event.
+/// At that point, adding an event to the stream is equivalent to
+/// returning to the event loop and adding the event in the next microtask.
+///
+/// Each listener callback will be run as if it was a top-level event
+/// or microtask. This means that if it throws, the error will be reported as
+/// uncaught as soon as possible.
+/// This is one reason to add the event as the last thing in the original event
+/// handler - any action done after adding the event will delay the report of
+/// errors in the event listener callbacks.
+///
+/// If an event is added in a setting that isn't known to be another event,
+/// it may cause the stream's listener to get that event before the listener
+/// is ready to handle it. We promise that after calling [Stream.listen],
+/// you won't get any events until the code doing the listen has completed.
+/// Calling [add] in response to a function call of unknown origin may break
+/// that promise.
+///
+/// An [onListen] callback from the controller is *not* an asynchronous event,
+/// and adding events to the controller in the `onListen` callback is always
+/// wrong. The events will be delivered before the listener has even received
+/// the subscription yet.
+///
+/// The synchronous broadcast stream controller also has a restrictions that a
+/// normal stream controller does not:
+/// The [add], [addError], [close] and [addStream] methods *must not* be
+/// called while an event is being delivered.
+/// That is, if a callback on a subscription on the controller's stream causes
+/// a call to any of the functions above, the call will fail.
+/// A broadcast stream may have more than one listener, and if an
+/// event is added synchronously while another is being also in the process
+/// of being added, the latter event might reach some listeners before
+/// the former. To prevent that, an event cannot be added while a previous
+/// event is being fired.
+/// This guarantees that an event is fully delivered when the
+/// first [add], [addError] or [close] returns,
+/// and further events will be delivered in the correct order.
+///
+/// This still only guarantees that the event is delivered to the subscription.
+/// If the subscription is paused, the actual callback may still happen later,
+/// and the event will instead be buffered by the subscription.
+/// Barring pausing, and the following buffered events that haven't been
+/// delivered yet, callbacks will be called synchronously when an event is added.
+///
+/// Adding an event to a synchronous non-broadcast stream controller while
+/// another event is in progress may cause the second event to be delayed
+/// and not be delivered synchronously, and until that event is delivered,
+/// the controller will not act synchronously.
 abstract class SynchronousStreamController<T> implements StreamController<T> {
-  /**
-   * Adds event to the controller's stream.
-   *
-   * As [StreamController.add], but must not be called while an event is
-   * being added by [add], [addError] or [close].
-   */
+  /// Adds event to the controller's stream.
+  ///
+  /// As [StreamController.add], but must not be called while an event is
+  /// being added by [add], [addError] or [close].
   void add(T data);
 
-  /**
-   * Adds error to the controller's stream.
-   *
-   * As [StreamController.addError], but must not be called while an event is
-   * being added by [add], [addError] or [close].
-   */
+  /// Adds error to the controller's stream.
+  ///
+  /// As [StreamController.addError], but must not be called while an event is
+  /// being added by [add], [addError] or [close].
   void addError(Object error, [StackTrace? stackTrace]);
 
-  /**
-   * Closes the controller's stream.
-   *
-   * As [StreamController.close], but must not be called while an event is
-   * being added by [add], [addError] or [close].
-   */
+  /// Closes the controller's stream.
+  ///
+  /// As [StreamController.close], but must not be called while an event is
+  /// being added by [add], [addError] or [close].
   Future close();
 }
 
@@ -414,11 +364,9 @@
         _EventSink<T>,
         _EventDispatch<T> {}
 
-/**
- * Default implementation of [StreamController].
- *
- * Controls a stream that only supports a single controller.
- */
+/// Default implementation of [StreamController].
+///
+/// Controls a stream that only supports a single controller.
 abstract class _StreamController<T> implements _StreamControllerBase<T> {
   // The states are bit-flags. More than one can be set at a time.
   //
@@ -430,18 +378,19 @@
   // subscription, the done event is queued. If done after cancel, the done
   // event is ignored (just as any other event after a cancel).
 
-  /** The controller is in its initial state with no subscription. */
+  /// The controller is in its initial state with no subscription.
   static const int _STATE_INITIAL = 0;
-  /**
-   * The controller has a subscription, but hasn't been closed or canceled.
-   *
-   * Keep in sync with
-   * runtime/vm/stack_trace.cc:kStreamController_StateSubscribed.
-   */
+
+  /// The controller has a subscription, but hasn't been closed or canceled.
+  ///
+  /// Keep in sync with
+  /// runtime/vm/stack_trace.cc:kStreamController_StateSubscribed.
   static const int _STATE_SUBSCRIBED = 1;
-  /** The subscription is canceled. */
+
+  /// The subscription is canceled.
   static const int _STATE_CANCELED = 2;
-  /** Mask for the subscription state. */
+
+  /// Mask for the subscription state.
   static const int _STATE_SUBSCRIPTION_MASK = 3;
 
   // The following state relate to the controller, not the subscription.
@@ -449,45 +398,38 @@
   // If executing an [addStream], new events are not allowed either, but will
   // be added by the stream.
 
-  /**
-   * The controller is closed due to calling [close].
-   *
-   * When the stream is closed, you can neither add new events nor add new
-   * listeners.
-   */
+  /// The controller is closed due to calling [close].
+  ///
+  /// When the stream is closed, you can neither add new events nor add new
+  /// listeners.
   static const int _STATE_CLOSED = 4;
-  /**
-   * The controller is in the middle of an [addStream] operation.
-   *
-   * While adding events from a stream, no new events can be added directly
-   * on the controller.
-   */
+
+  /// The controller is in the middle of an [addStream] operation.
+  ///
+  /// While adding events from a stream, no new events can be added directly
+  /// on the controller.
   static const int _STATE_ADDSTREAM = 8;
 
-  /**
-   * Field containing different data depending on the current subscription
-   * state.
-   *
-   * If [_state] is [_STATE_INITIAL], the field may contain a [_PendingEvents]
-   * for events added to the controller before a subscription.
-   *
-   * While [_state] is [_STATE_SUBSCRIBED], the field contains the subscription.
-   *
-   * When [_state] is [_STATE_CANCELED] the field is currently not used,
-   * and will contain `null`.
-   */
+  /// Field containing different data depending on the current subscription
+  /// state.
+  ///
+  /// If [_state] is [_STATE_INITIAL], the field may contain a [_PendingEvents]
+  /// for events added to the controller before a subscription.
+  ///
+  /// While [_state] is [_STATE_SUBSCRIBED], the field contains the subscription.
+  ///
+  /// When [_state] is [_STATE_CANCELED] the field is currently not used,
+  /// and will contain `null`.
   @pragma("vm:entry-point")
   Object? _varData;
 
-  /** Current state of the controller. */
+  /// Current state of the controller.
   @pragma("vm:entry-point")
   int _state = _STATE_INITIAL;
 
-  /**
-   * Future completed when the stream sends its last event.
-   *
-   * This is also the future returned by [close].
-   */
+  /// Future completed when the stream sends its last event.
+  ///
+  /// This is also the future returned by [close].
   // TODO(lrn): Could this be stored in the varData field too, if it's not
   // accessed until the call to "close"? Then we need to special case if it's
   // accessed earlier, or if close is called before subscribing.
@@ -503,22 +445,18 @@
   // Return a new stream every time. The streams are equal, but not identical.
   Stream<T> get stream => _ControllerStream<T>(this);
 
-  /**
-   * Returns a view of this object that only exposes the [StreamSink] interface.
-   */
+  /// Returns a view of this object that only exposes the [StreamSink] interface.
   StreamSink<T> get sink => _StreamSinkWrapper<T>(this);
 
-  /**
-   * Whether a listener has existed and been canceled.
-   *
-   * After this, adding more events will be ignored.
-   */
+  /// Whether a listener has existed and been canceled.
+  ///
+  /// After this, adding more events will be ignored.
   bool get _isCanceled => (_state & _STATE_CANCELED) != 0;
 
-  /** Whether there is an active listener. */
+  /// Whether there is an active listener.
   bool get hasListener => (_state & _STATE_SUBSCRIBED) != 0;
 
-  /** Whether there has not been a listener yet. */
+  /// Whether there has not been a listener yet.
   bool get _isInitialState =>
       (_state & _STATE_SUBSCRIPTION_MASK) == _STATE_INITIAL;
 
@@ -529,7 +467,7 @@
 
   bool get _isAddingStream => (_state & _STATE_ADDSTREAM) != 0;
 
-  /** New events may not be added after close, or during addStream. */
+  /// New events may not be added after close, or during addStream.
   bool get _mayAddEvent => (_state < _STATE_CLOSED);
 
   // Returns the pending events.
@@ -579,11 +517,9 @@
     return varData as dynamic;
   }
 
-  /**
-   * Creates an error describing why an event cannot be added.
-   *
-   * The reason, and therefore the error message, depends on the current state.
-   */
+  /// Creates an error describing why an event cannot be added.
+  ///
+  /// The reason, and therefore the error message, depends on the current state.
   Error _badEventState() {
     if (isClosed) {
       return StateError("Cannot add event after closing");
@@ -604,29 +540,23 @@
     return addState.addStreamFuture;
   }
 
-  /**
-   * Returns a future that is completed when the stream is done
-   * processing events.
-   *
-   * This happens either when the done event has been sent, or if the
-   * subscriber of a single-subscription stream is cancelled.
-   */
+  /// Returns a future that is completed when the stream is done
+  /// processing events.
+  ///
+  /// This happens either when the done event has been sent, or if the
+  /// subscriber of a single-subscription stream is cancelled.
   Future<void> get done => _ensureDoneFuture();
 
   Future<void> _ensureDoneFuture() =>
       _doneFuture ??= _isCanceled ? Future._nullFuture : _Future<void>();
 
-  /**
-   * Send or enqueue a data event.
-   */
+  /// Send or enqueue a data event.
   void add(T value) {
     if (!_mayAddEvent) throw _badEventState();
     _add(value);
   }
 
-  /**
-   * Send or enqueue an error event.
-   */
+  /// Send or enqueue an error event.
   void addError(Object error, [StackTrace? stackTrace]) {
     checkNotNullable(error, "error");
     if (!_mayAddEvent) throw _badEventState();
@@ -641,20 +571,18 @@
     _addError(error, stackTrace);
   }
 
-  /**
-   * Closes this controller and sends a done event on the stream.
-   *
-   * The first time a controller is closed, a "done" event is added to its
-   * stream.
-   *
-   * You are allowed to close the controller more than once, but only the first
-   * call has any effect.
-   *
-   * After closing, no further events may be added using [add], [addError]
-   * or [addStream].
-   *
-   * The returned future is completed when the done event has been delivered.
-   */
+  /// Closes this controller and sends a done event on the stream.
+  ///
+  /// The first time a controller is closed, a "done" event is added to its
+  /// stream.
+  ///
+  /// You are allowed to close the controller more than once, but only the first
+  /// call has any effect.
+  ///
+  /// After closing, no further events may be added using [add], [addError]
+  /// or [addStream].
+  ///
+  /// The returned future is completed when the done event has been delivered.
   Future close() {
     if (isClosed) {
       return _ensureDoneFuture();
@@ -892,7 +820,7 @@
   }
 }
 
-/** A class that exposes only the [StreamSink] interface of an object. */
+/// A class that exposes only the [StreamSink] interface of an object.
 class _StreamSinkWrapper<T> implements StreamSink<T> {
   final StreamController _target;
   _StreamSinkWrapper(this._target);
@@ -911,9 +839,7 @@
   Future get done => _target.done;
 }
 
-/**
- * Object containing the state used to handle [StreamController.addStream].
- */
+/// Object containing the state used to handle [StreamController.addStream].
 class _AddStreamState<T> {
   // [_Future] returned by call to addStream.
   final _Future addStreamFuture;
@@ -944,14 +870,12 @@
     addSubscription.resume();
   }
 
-  /**
-   * Stop adding the stream.
-   *
-   * Complete the future returned by `StreamController.addStream` when
-   * the cancel is complete.
-   *
-   * Return a future if the cancel takes time, otherwise return `null`.
-   */
+  /// Stop adding the stream.
+  ///
+  /// Complete the future returned by `StreamController.addStream` when
+  /// the cancel is complete.
+  ///
+  /// Return a future if the cancel takes time, otherwise return `null`.
   Future<void> cancel() {
     var cancel = addSubscription.cancel();
     if (cancel == null) {
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index bb4a1ba..02c4504 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -4,83 +4,75 @@
 
 part of dart.async;
 
-/** Abstract and private interface for a place to put events. */
+/// Abstract and private interface for a place to put events.
 abstract class _EventSink<T> {
   void _add(T data);
   void _addError(Object error, StackTrace stackTrace);
   void _close();
 }
 
-/**
- * Abstract and private interface for a place to send events.
- *
- * Used by event buffering to finally dispatch the pending event, where
- * [_EventSink] is where the event first enters the stream subscription,
- * and may yet be buffered.
- */
+/// Abstract and private interface for a place to send events.
+///
+/// Used by event buffering to finally dispatch the pending event, where
+/// [_EventSink] is where the event first enters the stream subscription,
+/// and may yet be buffered.
 abstract class _EventDispatch<T> {
   void _sendData(T data);
   void _sendError(Object error, StackTrace stackTrace);
   void _sendDone();
 }
 
-/**
- * Default implementation of stream subscription of buffering events.
- *
- * The only public methods are those of [StreamSubscription], so instances of
- * [_BufferingStreamSubscription] can be returned directly as a
- * [StreamSubscription] without exposing internal functionality.
- *
- * The [StreamController] is a public facing version of [Stream] and this class,
- * with some methods made public.
- *
- * The user interface of [_BufferingStreamSubscription] are the following
- * methods:
- *
- * * [_add]: Add a data event to the stream.
- * * [_addError]: Add an error event to the stream.
- * * [_close]: Request to close the stream.
- * * [_onCancel]: Called when the subscription will provide no more events,
- *     either due to being actively canceled, or after sending a done event.
- * * [_onPause]: Called when the subscription wants the event source to pause.
- * * [_onResume]: Called when allowing new events after a pause.
- *
- * The user should not add new events when the subscription requests a paused,
- * but if it happens anyway, the subscription will enqueue the events just as
- * when new events arrive while still firing an old event.
- */
+/// Default implementation of stream subscription of buffering events.
+///
+/// The only public methods are those of [StreamSubscription], so instances of
+/// [_BufferingStreamSubscription] can be returned directly as a
+/// [StreamSubscription] without exposing internal functionality.
+///
+/// The [StreamController] is a public facing version of [Stream] and this class,
+/// with some methods made public.
+///
+/// The user interface of [_BufferingStreamSubscription] are the following
+/// methods:
+///
+/// * [_add]: Add a data event to the stream.
+/// * [_addError]: Add an error event to the stream.
+/// * [_close]: Request to close the stream.
+/// * [_onCancel]: Called when the subscription will provide no more events,
+///     either due to being actively canceled, or after sending a done event.
+/// * [_onPause]: Called when the subscription wants the event source to pause.
+/// * [_onResume]: Called when allowing new events after a pause.
+///
+/// The user should not add new events when the subscription requests a paused,
+/// but if it happens anyway, the subscription will enqueue the events just as
+/// when new events arrive while still firing an old event.
 class _BufferingStreamSubscription<T>
     implements StreamSubscription<T>, _EventSink<T>, _EventDispatch<T> {
-  /** The `cancelOnError` flag from the `listen` call. */
+  /// The `cancelOnError` flag from the `listen` call.
   static const int _STATE_CANCEL_ON_ERROR = 1;
-  /**
-   * Whether the "done" event has been received.
-   * No further events are accepted after this.
-   */
+
+  /// Whether the "done" event has been received.
+  /// No further events are accepted after this.
   static const int _STATE_CLOSED = 2;
-  /**
-   * Set if the input has been asked not to send events.
-   *
-   * This is not the same as being paused, since the input will remain paused
-   * after a call to [resume] if there are pending events.
-   */
+
+  /// Set if the input has been asked not to send events.
+  ///
+  /// This is not the same as being paused, since the input will remain paused
+  /// after a call to [resume] if there are pending events.
   static const int _STATE_INPUT_PAUSED = 4;
-  /**
-   * Whether the subscription has been canceled.
-   *
-   * Set by calling [cancel], or by handling a "done" event, or an "error" event
-   * when `cancelOnError` is true.
-   */
+
+  /// Whether the subscription has been canceled.
+  ///
+  /// Set by calling [cancel], or by handling a "done" event, or an "error" event
+  /// when `cancelOnError` is true.
   static const int _STATE_CANCELED = 8;
-  /**
-   * Set when either:
-   *
-   *   * an error is sent, and [cancelOnError] is true, or
-   *   * a done event is sent.
-   *
-   * If the subscription is canceled while _STATE_WAIT_FOR_CANCEL is set, the
-   * state is unset, and no further events must be delivered.
-   */
+
+  /// Set when either:
+  ///
+  ///   * an error is sent, and [cancelOnError] is true, or
+  ///   * a done event is sent.
+  ///
+  /// If the subscription is canceled while _STATE_WAIT_FOR_CANCEL is set, the
+  /// state is unset, and no further events must be delivered.
   static const int _STATE_WAIT_FOR_CANCEL = 16;
   static const int _STATE_IN_CALLBACK = 32;
   static const int _STATE_HAS_PENDING = 64;
@@ -94,18 +86,16 @@
 
   final Zone _zone;
 
-  /** Bit vector based on state-constants above. */
+  /// Bit vector based on state-constants above.
   int _state;
 
   // TODO(floitsch): reuse another field
-  /** The future [_onCancel] may return. */
+  /// The future [_onCancel] may return.
   Future? _cancelFuture;
 
-  /**
-   * Queue of pending events.
-   *
-   * Is created when necessary, or set in constructor for preconfigured events.
-   */
+  /// Queue of pending events.
+  ///
+  /// Is created when necessary, or set in constructor for preconfigured events.
   _PendingEvents<T>? _pending;
 
   _BufferingStreamSubscription(void onData(T data)?, Function? onError,
@@ -119,12 +109,10 @@
         _onError = _registerErrorHandler(_zone, onError),
         _onDone = _registerDoneHandler(_zone, onDone);
 
-  /**
-   * Sets the subscription's pending events object.
-   *
-   * This can only be done once. The pending events object is used for the
-   * rest of the subscription's life cycle.
-   */
+  /// Sets the subscription's pending events object.
+  ///
+  /// This can only be done once. The pending events object is used for the
+  /// rest of the subscription's life cycle.
   void _setPendingEvents(_PendingEvents<T>? pendingEvents) {
     assert(_pending == null);
     if (pendingEvents == null) return;
@@ -264,13 +252,11 @@
     _cancelFuture = _onCancel();
   }
 
-  /**
-   * Decrements the pause count.
-   *
-   * Does not automatically unpause the input (call [_onResume]) when
-   * the pause count reaches zero. This is handled elsewhere, and only
-   * if there are no pending events buffered.
-   */
+  /// Decrements the pause count.
+  ///
+  /// Does not automatically unpause the input (call [_onResume]) when
+  /// the pause count reaches zero. This is handled elsewhere, and only
+  /// if there are no pending events buffered.
   void _decrementPauseCount() {
     assert(_isPaused);
     _state -= _STATE_PAUSE_COUNT;
@@ -327,12 +313,10 @@
 
   // Handle pending events.
 
-  /**
-   * Add a pending event.
-   *
-   * If the subscription is not paused, this also schedules a firing
-   * of pending events later (if necessary).
-   */
+  /// Add a pending event.
+  ///
+  /// If the subscription is not paused, this also schedules a firing
+  /// of pending events later (if necessary).
   void _addPending(_DelayedEvent event) {
     _StreamImplEvents<T>? pending = _pending as dynamic;
     pending ??= _StreamImplEvents<T>();
@@ -421,13 +405,11 @@
     }
   }
 
-  /**
-   * Call a hook function.
-   *
-   * The call is properly wrapped in code to avoid other callbacks
-   * during the call, and it checks for state changes after the call
-   * that should cause further callbacks.
-   */
+  /// Call a hook function.
+  ///
+  /// The call is properly wrapped in code to avoid other callbacks
+  /// during the call, and it checks for state changes after the call
+  /// that should cause further callbacks.
   void _guardCallback(void Function() callback) {
     assert(!_inCallback);
     bool wasInputPaused = _isInputPaused;
@@ -437,16 +419,14 @@
     _checkState(wasInputPaused);
   }
 
-  /**
-   * Check if the input needs to be informed of state changes.
-   *
-   * State changes are pausing, resuming and canceling.
-   *
-   * After canceling, no further callbacks will happen.
-   *
-   * The cancel callback is called after a user cancel, or after
-   * the final done event is sent.
-   */
+  /// Check if the input needs to be informed of state changes.
+  ///
+  /// State changes are pausing, resuming and canceling.
+  ///
+  /// After canceling, no further callbacks will happen.
+  ///
+  /// The cancel callback is called after a user cancel, or after
+  /// the final done event is sent.
   void _checkState(bool wasInputPaused) {
     assert(!_inCallback);
     if (_hasPending && _pending!.isEmpty) {
@@ -496,29 +476,28 @@
   }
 
   // -------------------------------------------------------------------
-  /** Create a subscription object. Called by [subcribe]. */
+  /// Create a subscription object. Called by [subcribe].
   StreamSubscription<T> _createSubscription(void onData(T data)?,
       Function? onError, void onDone()?, bool cancelOnError) {
     return new _BufferingStreamSubscription<T>(
         onData, onError, onDone, cancelOnError);
   }
 
-  /** Hook called when the subscription has been created. */
+  /// Hook called when the subscription has been created.
   void _onListen(StreamSubscription subscription) {}
 }
 
 typedef _PendingEvents<T> _EventGenerator<T>();
 
-/** Stream that generates its own events. */
+/// Stream that generates its own events.
 class _GeneratedStreamImpl<T> extends _StreamImpl<T> {
   final _EventGenerator<T> _pending;
   bool _isUsed = false;
-  /**
-   * Initializes the stream to have only the events provided by a
-   * [_PendingEvents].
-   *
-   * A new [_PendingEvents] must be generated for each listen.
-   */
+
+  /// Initializes the stream to have only the events provided by a
+  /// [_PendingEvents].
+  ///
+  /// A new [_PendingEvents] must be generated for each listen.
   _GeneratedStreamImpl(this._pending);
 
   StreamSubscription<T> _createSubscription(void onData(T data)?,
@@ -531,7 +510,7 @@
   }
 }
 
-/** Pending events object that gets its events from an [Iterable]. */
+/// Pending events object that gets its events from an [Iterable].
 class _IterablePendingEvents<T> extends _PendingEvents<T> {
   // The iterator providing data for data events.
   // Set to null when iteration has completed.
@@ -584,26 +563,27 @@
 typedef void _DataHandler<T>(T value);
 typedef void _DoneHandler();
 
-/** Default data handler, does nothing. */
+/// Default data handler, does nothing.
 void _nullDataHandler(dynamic value) {}
 
-/** Default error handler, reports the error to the current zone's handler. */
+/// Default error handler, reports the error to the current zone's handler.
 void _nullErrorHandler(Object error, StackTrace stackTrace) {
   Zone.current.handleUncaughtError(error, stackTrace);
 }
 
-/** Default done handler, does nothing. */
+/// Default done handler, does nothing.
 void _nullDoneHandler() {}
 
-/** A delayed event on a buffering stream subscription. */
+/// A delayed event on a buffering stream subscription.
 abstract class _DelayedEvent<T> {
-  /** Added as a linked list on the [StreamController]. */
+  /// Added as a linked list on the [StreamController].
   _DelayedEvent? next;
-  /** Execute the delayed event on the [StreamController]. */
+
+  /// Execute the delayed event on the [StreamController].
   void perform(_EventDispatch<T> dispatch);
 }
 
-/** A delayed data event. */
+/// A delayed data event.
 class _DelayedData<T> extends _DelayedEvent<T> {
   final T value;
   _DelayedData(this.value);
@@ -612,7 +592,7 @@
   }
 }
 
-/** A delayed error event. */
+/// A delayed error event.
 class _DelayedError extends _DelayedEvent {
   final Object error;
   final StackTrace stackTrace;
@@ -623,7 +603,7 @@
   }
 }
 
-/** A delayed done event. */
+/// A delayed done event.
 class _DelayedDone implements _DelayedEvent {
   const _DelayedDone();
   void perform(_EventDispatch dispatch) {
@@ -637,7 +617,7 @@
   }
 }
 
-/** Superclass for provider of pending events. */
+/// Superclass for provider of pending events.
 abstract class _PendingEvents<T> {
   // No async event has been scheduled.
   static const int _STATE_UNSCHEDULED = 0;
@@ -647,18 +627,16 @@
   // Async events can't be preempted.
   static const int _STATE_CANCELED = 3;
 
-  /**
-   * State of being scheduled.
-   *
-   * Set to [_STATE_SCHEDULED] when pending events are scheduled for
-   * async dispatch. Since we can't cancel a [scheduleMicrotask] call, if
-   * scheduling is "canceled", the _state is simply set to [_STATE_CANCELED]
-   * which will make the async code do nothing except resetting [_state].
-   *
-   * If events are scheduled while the state is [_STATE_CANCELED], it is
-   * merely switched back to [_STATE_SCHEDULED], but no new call to
-   * [scheduleMicrotask] is performed.
-   */
+  /// State of being scheduled.
+  ///
+  /// Set to [_STATE_SCHEDULED] when pending events are scheduled for
+  /// async dispatch. Since we can't cancel a [scheduleMicrotask] call, if
+  /// scheduling is "canceled", the _state is simply set to [_STATE_CANCELED]
+  /// which will make the async code do nothing except resetting [_state].
+  ///
+  /// If events are scheduled while the state is [_STATE_CANCELED], it is
+  /// merely switched back to [_STATE_SCHEDULED], but no new call to
+  /// [scheduleMicrotask] is performed.
   int _state = _STATE_UNSCHEDULED;
 
   bool get isEmpty;
@@ -666,12 +644,10 @@
   bool get isScheduled => _state == _STATE_SCHEDULED;
   bool get _eventScheduled => _state >= _STATE_SCHEDULED;
 
-  /**
-   * Schedule an event to run later.
-   *
-   * If called more than once, it should be called with the same dispatch as
-   * argument each time. It may reuse an earlier argument in some cases.
-   */
+  /// Schedule an event to run later.
+  ///
+  /// If called more than once, it should be called with the same dispatch as
+  /// argument each time. It may reuse an earlier argument in some cases.
   void schedule(_EventDispatch<T> dispatch) {
     if (isScheduled) return;
     assert(!isEmpty);
@@ -695,11 +671,11 @@
 
   void handleNext(_EventDispatch<T> dispatch);
 
-  /** Throw away any pending events and cancel scheduled events. */
+  /// Throw away any pending events and cancel scheduled events.
   void clear();
 }
 
-/** Class holding pending events for a [_StreamImpl]. */
+/// Class holding pending events for a [_StreamImpl].
 class _StreamImplEvents<T> extends _PendingEvents<T> {
   /// Single linked list of [_DelayedEvent] objects.
   _DelayedEvent? firstPendingEvent;
@@ -738,9 +714,7 @@
 
 typedef void _BroadcastCallback<T>(StreamSubscription<T> subscription);
 
-/**
- * Done subscription that will send one done event as soon as possible.
- */
+/// Done subscription that will send one done event as soon as possible.
 class _DoneStreamSubscription<T> implements StreamSubscription<T> {
   static const int _DONE_SENT = 1;
   static const int _SCHEDULED = 2;
@@ -900,9 +874,7 @@
   }
 }
 
-/**
- * Wrapper for subscription that disallows changing handlers.
- */
+/// Wrapper for subscription that disallows changing handlers.
 class _BroadcastSubscriptionWrapper<T> implements StreamSubscription<T> {
   final _AsBroadcastStream _stream;
 
@@ -1118,7 +1090,7 @@
   }
 }
 
-/** An empty broadcast stream, sending a done event as soon as possible. */
+/// An empty broadcast stream, sending a done event as soon as possible.
 class _EmptyStream<T> extends Stream<T> {
   const _EmptyStream() : super._internal();
   bool get isBroadcast => true;
@@ -1128,10 +1100,11 @@
   }
 }
 
-/** A stream which creates a new controller for each listener. */
+/// A stream which creates a new controller for each listener.
 class _MultiStream<T> extends Stream<T> {
   final bool isBroadcast;
-  /** The callback called for each listen. */
+
+  /// The callback called for each listen.
   final void Function(MultiStreamController<T>) _onListen;
 
   _MultiStream(this._onListen, this.isBroadcast);
diff --git a/sdk/lib/async/stream_pipe.dart b/sdk/lib/async/stream_pipe.dart
index fd20228..60aff7e 100644
--- a/sdk/lib/async/stream_pipe.dart
+++ b/sdk/lib/async/stream_pipe.dart
@@ -4,7 +4,7 @@
 
 part of dart.async;
 
-/** Runs user code and takes actions depending on success or failure. */
+/// Runs user code and takes actions depending on success or failure.
 _runUserCode<T>(T userCode(), onSuccess(T value),
     onError(Object error, StackTrace stackTrace)) {
   try {
@@ -43,7 +43,7 @@
   _cancelAndError(subscription, future, error, stackTrace);
 }
 
-/** Helper function to make an onError argument to [_runUserCode]. */
+/// Helper function to make an onError argument to [_runUserCode].
 void Function(Object error, StackTrace stackTrace) _cancelAndErrorClosure(
     StreamSubscription subscription, _Future future) {
   return (Object error, StackTrace stackTrace) {
@@ -62,15 +62,13 @@
   }
 }
 
-/**
- * A [Stream] that forwards subscriptions to another stream.
- *
- * This stream implements [Stream], but forwards all subscriptions
- * to an underlying stream, and wraps the returned subscription to
- * modify the events on the way.
- *
- * This class is intended for internal use only.
- */
+/// A [Stream] that forwards subscriptions to another stream.
+///
+/// This stream implements [Stream], but forwards all subscriptions
+/// to an underlying stream, and wraps the returned subscription to
+/// modify the events on the way.
+///
+/// This class is intended for internal use only.
 abstract class _ForwardingStream<S, T> extends Stream<T> {
   final Stream<S> _source;
 
@@ -102,9 +100,7 @@
   }
 }
 
-/**
- * Abstract superclass for subscriptions that forward to other subscriptions.
- */
+/// Abstract superclass for subscriptions that forward to other subscriptions.
 class _ForwardingStreamSubscription<S, T>
     extends _BufferingStreamSubscription<T> {
   final _ForwardingStream<S, T> _stream;
@@ -203,9 +199,7 @@
 
 typedef T _Transformation<S, T>(S value);
 
-/**
- * A stream pipe that converts data events before passing them on.
- */
+/// A stream pipe that converts data events before passing them on.
 class _MapStream<S, T> extends _ForwardingStream<S, T> {
   final _Transformation<S, T> _transform;
 
@@ -225,9 +219,7 @@
   }
 }
 
-/**
- * A stream pipe that converts data events before passing them on.
- */
+/// A stream pipe that converts data events before passing them on.
 class _ExpandStream<S, T> extends _ForwardingStream<S, T> {
   final _Transformation<S, Iterable<T>> _expand;
 
@@ -248,10 +240,8 @@
   }
 }
 
-/**
- * A stream pipe that converts or disposes error events
- * before passing them on.
- */
+/// A stream pipe that converts or disposes error events
+/// before passing them on.
 class _HandleErrorStream<T> extends _ForwardingStream<T, T> {
   final Function _transform;
   final bool Function(Object)? _test;
@@ -327,11 +317,9 @@
   }
 }
 
-/**
- * A [_ForwardingStreamSubscription] with one extra state field.
- *
- * Use by several different classes, storing an integer, bool or general.
- */
+/// A [_ForwardingStreamSubscription] with one extra state field.
+///
+/// Use by several different classes, storing an integer, bool or general.
 class _StateStreamSubscription<S, T>
     extends _ForwardingStreamSubscription<T, T> {
   S _subState;
diff --git a/sdk/lib/async/stream_transformers.dart b/sdk/lib/async/stream_transformers.dart
index aa99f5f..9193071 100644
--- a/sdk/lib/async/stream_transformers.dart
+++ b/sdk/lib/async/stream_transformers.dart
@@ -4,9 +4,7 @@
 
 part of dart.async;
 
-/**
- * Wraps an [_EventSink] so it exposes only the [EventSink] interface.
- */
+/// Wraps an [_EventSink] so it exposes only the [EventSink] interface.
 class _EventSinkWrapper<T> implements EventSink<T> {
   _EventSink<T> _sink;
   _EventSinkWrapper(this._sink);
@@ -24,13 +22,11 @@
   }
 }
 
-/**
- * A StreamSubscription that pipes data through a sink.
- *
- * The constructor of this class takes a [_SinkMapper] which maps from
- * [EventSink] to [EventSink]. The input to the mapper is the output of
- * the transformation. The returned sink is the transformation's input.
- */
+/// A StreamSubscription that pipes data through a sink.
+///
+/// The constructor of this class takes a [_SinkMapper] which maps from
+/// [EventSink] to [EventSink]. The input to the mapper is the output of
+/// the transformation. The returned sink is the transformation's input.
 class _SinkTransformerStreamSubscription<S, T>
     extends _BufferingStreamSubscription<T> {
   /// The transformer's input sink.
@@ -55,13 +51,11 @@
 
   // _EventSink interface.
 
-  /**
-   * Adds an event to this subscriptions.
-   *
-   * Contrary to normal [_BufferingStreamSubscription]s we may receive
-   * events when the stream is already closed. Report them as state
-   * error.
-   */
+  /// Adds an event to this subscriptions.
+  ///
+  /// Contrary to normal [_BufferingStreamSubscription]s we may receive
+  /// events when the stream is already closed. Report them as state
+  /// error.
   void _add(T data) {
     if (_isClosed) {
       throw StateError("Stream is already closed");
@@ -69,13 +63,11 @@
     super._add(data);
   }
 
-  /**
-   * Adds an error event to this subscriptions.
-   *
-   * Contrary to normal [_BufferingStreamSubscription]s we may receive
-   * events when the stream is already closed. Report them as state
-   * error.
-   */
+  /// Adds an error event to this subscriptions.
+  ///
+  /// Contrary to normal [_BufferingStreamSubscription]s we may receive
+  /// events when the stream is already closed. Report them as state
+  /// error.
   void _addError(Object error, StackTrace stackTrace) {
     if (_isClosed) {
       throw new StateError("Stream is already closed");
@@ -83,13 +75,11 @@
     super._addError(error, stackTrace);
   }
 
-  /**
-   * Adds a close event to this subscriptions.
-   *
-   * Contrary to normal [_BufferingStreamSubscription]s we may receive
-   * events when the stream is already closed. Report them as state
-   * error.
-   */
+  /// Adds a close event to this subscriptions.
+  ///
+  /// Contrary to normal [_BufferingStreamSubscription]s we may receive
+  /// events when the stream is already closed. Report them as state
+  /// error.
   void _close() {
     if (_isClosed) {
       throw new StateError("Stream is already closed");
@@ -148,14 +138,12 @@
 
 typedef EventSink<S> _SinkMapper<S, T>(EventSink<T> output);
 
-/**
- * A StreamTransformer for Sink-mappers.
- *
- * A Sink-mapper takes an [EventSink] (its output) and returns another
- * EventSink (its input).
- *
- * Note that this class can be `const`.
- */
+/// A [StreamTransformer] for [Sink]-mappers.
+///
+/// A Sink-mapper takes an [EventSink] (its output) and returns another
+/// [EventSink] (its input).
+///
+/// Note that this class can be `const`.
 class _StreamSinkTransformer<S, T> extends StreamTransformerBase<S, T> {
   final _SinkMapper<S, T> _sinkMapper;
   const _StreamSinkTransformer(this._sinkMapper);
@@ -164,13 +152,11 @@
       new _BoundSinkStream<S, T>(stream, _sinkMapper);
 }
 
-/**
- * The result of binding a StreamTransformer for Sink-mappers.
- *
- * It contains the bound Stream and the sink-mapper. Only when the user starts
- * listening to this stream is the sink-mapper invoked. The result is used
- * to create a StreamSubscription that transforms events.
- */
+/// The result of binding a [StreamTransformer] for [Sink]-mappers.
+///
+/// It contains the bound Stream and the sink-mapper. Only when the user starts
+/// listening to this stream is the sink-mapper invoked. The result is used
+/// to create a StreamSubscription that transforms events.
 class _BoundSinkStream<S, T> extends Stream<T> {
   final _SinkMapper<S, T> _sinkMapper;
   final Stream<S> _stream;
@@ -198,11 +184,9 @@
 /// Done-handler coming from [StreamTransformer.fromHandlers].
 typedef void _TransformDoneHandler<T>(EventSink<T> sink);
 
-/**
- * Wraps handlers (from [StreamTransformer.fromHandlers]) into an `EventSink`.
- *
- * This way we can reuse the code from [_StreamSinkTransformer].
- */
+/// Wraps handlers (from [StreamTransformer.fromHandlers]) into an `EventSink`.
+///
+/// This way we can reuse the code from [_StreamSinkTransformer].
 class _HandlerEventSink<S, T> implements EventSink<S> {
   final _TransformDataHandler<S, T>? _handleData;
   final _TransformErrorHandler<T>? _handleError;
@@ -256,11 +240,9 @@
   }
 }
 
-/**
- * A StreamTransformer that transformers events with the given handlers.
- *
- * Note that this transformer can only be used once.
- */
+/// A StreamTransformer that transformers events with the given handlers.
+///
+/// Note that this transformer can only be used once.
 class _StreamHandlerTransformer<S, T> extends _StreamSinkTransformer<S, T> {
   _StreamHandlerTransformer(
       {void handleData(S data, EventSink<T> sink)?,
@@ -276,9 +258,7 @@
   }
 }
 
-/**
- * A StreamTransformer that overrides [StreamTransformer.bind] with a callback.
- */
+/// A StreamTransformer that overrides [StreamTransformer.bind] with a callback.
 class _StreamBindTransformer<S, T> extends StreamTransformerBase<S, T> {
   final Stream<T> Function(Stream<S>) _bind;
   _StreamBindTransformer(this._bind);
@@ -290,18 +270,16 @@
 typedef StreamSubscription<T> _SubscriptionTransformer<S, T>(
     Stream<S> stream, bool cancelOnError);
 
-/**
- * A [StreamTransformer] that minimizes the number of additional classes.
- *
- * Instead of implementing three classes: a [StreamTransformer], a [Stream]
- * (as the result of a `bind` call) and a [StreamSubscription] (which does the
- * actual work), this class only requires a function that is invoked when the
- * last bit (the subscription) of the transformer-workflow is needed.
- *
- * The given transformer function maps from Stream and cancelOnError to a
- * `StreamSubscription`. As such it can also act on `cancel` events, making it
- * fully general.
- */
+/// A [StreamTransformer] that minimizes the number of additional classes.
+///
+/// Instead of implementing three classes: a [StreamTransformer], a [Stream]
+/// (as the result of a `bind` call) and a [StreamSubscription] (which does the
+/// actual work), this class only requires a function that is invoked when the
+/// last bit (the subscription) of the transformer-workflow is needed.
+///
+/// The given transformer function maps from Stream and cancelOnError to a
+/// `StreamSubscription`. As such it can also act on `cancel` events, making it
+/// fully general.
 class _StreamSubscriptionTransformer<S, T> extends StreamTransformerBase<S, T> {
   final _SubscriptionTransformer<S, T> _onListen;
 
@@ -311,13 +289,11 @@
       new _BoundSubscriptionStream<S, T>(stream, _onListen);
 }
 
-/**
- * A stream transformed by a [_StreamSubscriptionTransformer].
- *
- * When this stream is listened to it invokes the [_onListen] function with
- * the stored [_stream]. Usually the transformer starts listening at this
- * moment.
- */
+/// A stream transformed by a [_StreamSubscriptionTransformer].
+///
+/// When this stream is listened to it invokes the [_onListen] function with
+/// the stored [_stream]. Usually the transformer starts listening at this
+/// moment.
 class _BoundSubscriptionStream<S, T> extends Stream<T> {
   final _SubscriptionTransformer<S, T> _onListen;
   final Stream<S> _stream;
diff --git a/sdk/lib/async/timer.dart b/sdk/lib/async/timer.dart
index e0ef447..973a543 100644
--- a/sdk/lib/async/timer.dart
+++ b/sdk/lib/async/timer.dart
@@ -4,44 +4,40 @@
 
 part of dart.async;
 
-/**
- * A count-down timer that can be configured to fire once or repeatedly.
- *
- * The timer counts down from the specified duration to 0.
- * When the timer reaches 0, the timer invokes the specified callback function.
- * Use a periodic timer to repeatedly count down the same interval.
- *
- * A negative duration is treated the same as a duration of 0.
- * If the duration is statically known to be 0, consider using [run].
- *
- * Frequently the duration is either a constant or computed as in the
- * following example (taking advantage of the multiplication operator of
- * the [Duration] class):
- * ```dart
- * const timeout = const Duration(seconds: 3);
- * const ms = const Duration(milliseconds: 1);
- *
- * startTimeout([int milliseconds]) {
- *   var duration = milliseconds == null ? timeout : ms * milliseconds;
- *   return new Timer(duration, handleTimeout);
- * }
- * ...
- * void handleTimeout() {  // callback function
- *   ...
- * }
- * ```
- * Note: If Dart code using Timer is compiled to JavaScript, the finest
- * granularity available in the browser is 4 milliseconds.
- *
- * See [Stopwatch] for measuring elapsed time.
- */
+/// A count-down timer that can be configured to fire once or repeatedly.
+///
+/// The timer counts down from the specified duration to 0.
+/// When the timer reaches 0, the timer invokes the specified callback function.
+/// Use a periodic timer to repeatedly count down the same interval.
+///
+/// A negative duration is treated the same as a duration of 0.
+/// If the duration is statically known to be 0, consider using [run].
+///
+/// Frequently the duration is either a constant or computed as in the
+/// following example (taking advantage of the multiplication operator of
+/// the [Duration] class):
+/// ```dart
+/// const timeout = Duration(seconds: 3);
+/// const ms = Duration(milliseconds: 1);
+///
+/// Timer startTimeout([int? milliseconds]) {
+///   var duration = milliseconds == null ? timeout : ms * milliseconds;
+///   return Timer(duration, handleTimeout);
+/// }
+/// ...
+/// void handleTimeout() {  // callback function
+///   ...
+/// }
+/// ```
+/// Note: If Dart code using [Timer] is compiled to JavaScript, the finest
+/// granularity available in the browser is 4 milliseconds.
+///
+/// See [Stopwatch] for measuring elapsed time.
 abstract class Timer {
-  /**
-   * Creates a new timer.
-   *
-   * The [callback] function is invoked after the given [duration].
-   *
-   */
+  /// Creates a new timer.
+  ///
+  /// The [callback] function is invoked after the given [duration].
+  ///
   factory Timer(Duration duration, void Function() callback) {
     if (Zone.current == Zone.root) {
       // No need to bind the callback. We know that the root's timer will
@@ -52,24 +48,22 @@
         .createTimer(duration, Zone.current.bindCallbackGuarded(callback));
   }
 
-  /**
-   * Creates a new repeating timer.
-   *
-   * The [callback] is invoked repeatedly with [duration] intervals until
-   * canceled with the [cancel] function.
-   *
-   * The exact timing depends on the underlying timer implementation.
-   * No more than `n` callbacks will be made in `duration * n` time,
-   * but the time between two consecutive callbacks
-   * can be shorter and longer than `duration`.
-   *
-   * In particular, an implementation may schedule the next callback, e.g.,
-   * a `duration` after either when the previous callback ended,
-   * when the previous callback started, or when the previous callback was
-   * scheduled for - even if the actual callback was delayed.
-   *
-   * [duration] must a non-negative [Duration].
-   */
+  /// Creates a new repeating timer.
+  ///
+  /// The [callback] is invoked repeatedly with [duration] intervals until
+  /// canceled with the [cancel] function.
+  ///
+  /// The exact timing depends on the underlying timer implementation.
+  /// No more than `n` callbacks will be made in `duration * n` time,
+  /// but the time between two consecutive callbacks
+  /// can be shorter and longer than `duration`.
+  ///
+  /// In particular, an implementation may schedule the next callback, e.g.,
+  /// a `duration` after either when the previous callback ended,
+  /// when the previous callback started, or when the previous callback was
+  /// scheduled for - even if the actual callback was delayed.
+  ///
+  /// [duration] must a non-negative [Duration].
   factory Timer.periodic(Duration duration, void callback(Timer timer)) {
     if (Zone.current == Zone.root) {
       // No need to bind the callback. We know that the root's timer will
@@ -80,47 +74,39 @@
     return Zone.current.createPeriodicTimer(duration, boundCallback);
   }
 
-  /**
-   * Runs the given [callback] asynchronously as soon as possible.
-   *
-   * This function is equivalent to `new Timer(Duration.zero, callback)`.
-   */
+  /// Runs the given [callback] asynchronously as soon as possible.
+  ///
+  /// This function is equivalent to `new Timer(Duration.zero, callback)`.
   static void run(void Function() callback) {
     new Timer(Duration.zero, callback);
   }
 
-  /**
-   * Cancels the timer.
-   *
-   * Once a [Timer] has been canceled, the callback function will not be called
-   * by the timer. Calling [cancel] more than once on a [Timer] is allowed, and
-   * will have no further effect.
-   */
+  /// Cancels the timer.
+  ///
+  /// Once a [Timer] has been canceled, the callback function will not be called
+  /// by the timer. Calling [cancel] more than once on a [Timer] is allowed, and
+  /// will have no further effect.
   void cancel();
 
-  /**
-   * The number of durations preceding the most recent timer event.
-   *
-   * The value starts at zero and is incremented each time a timer event
-   * occurs, so each callback will see a larger value than the previous one.
-   *
-   * If a periodic timer with a non-zero duration is delayed too much,
-   * so more than one tick should have happened,
-   * all but the last tick in the past are considered "missed",
-   * and no callback is invoked for them.
-   * The [tick] count reflects the number of durations that have passed and
-   * not the number of callback invocations that have happened.
-   */
+  /// The number of durations preceding the most recent timer event.
+  ///
+  /// The value starts at zero and is incremented each time a timer event
+  /// occurs, so each callback will see a larger value than the previous one.
+  ///
+  /// If a periodic timer with a non-zero duration is delayed too much,
+  /// so more than one tick should have happened,
+  /// all but the last tick in the past are considered "missed",
+  /// and no callback is invoked for them.
+  /// The [tick] count reflects the number of durations that have passed and
+  /// not the number of callback invocations that have happened.
   int get tick;
 
-  /**
-   * Returns whether the timer is still active.
-   *
-   * A non-periodic timer is active if the callback has not been executed,
-   * and the timer has not been canceled.
-   *
-   * A periodic timer is active if it has not been canceled.
-   */
+  /// Returns whether the timer is still active.
+  ///
+  /// A non-periodic timer is active if the callback has not been executed,
+  /// and the timer has not been canceled.
+  ///
+  /// A periodic timer is active if it has not been canceled.
   bool get isActive;
 
   external static Timer _createTimer(
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index f662d53..4f0873d 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -8,59 +8,236 @@
 typedef R ZoneUnaryCallback<R, T>(T arg);
 typedef R ZoneBinaryCallback<R, T1, T2>(T1 arg1, T2 arg2);
 
+/// The type of a custom [Zone.handleUncaughtError] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The [error] and [stackTrace] are the error and stack trace that
+/// was uncaught in [zone].
 typedef HandleUncaughtErrorHandler = void Function(Zone self,
     ZoneDelegate parent, Zone zone, Object error, StackTrace stackTrace);
+
+/// The type of a custom [Zone.run] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The function [f] is the function which was passed to the
+/// [Zone.run] of [zone].
+///
+/// The default behavior of [Zone.run] is
+/// to call [f] in the current zone, [zone].
+/// A custom handler can do things before, after or instead of
+/// calling [f].
 typedef RunHandler = R Function<R>(
     Zone self, ZoneDelegate parent, Zone zone, R Function() f);
+
+/// The type of a custom [Zone.runUnary] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The function [f] and value [arg] are the function and argument
+/// which was passed to the [Zone.runUnary] of [zone].
+///
+/// The default behavior of [Zone.runUnary] is
+/// to call [f] with argument [arg] in the current zone, [zone].
+/// A custom handler can do things before, after or instead of
+/// calling [f].
 typedef RunUnaryHandler = R Function<R, T>(
     Zone self, ZoneDelegate parent, Zone zone, R Function(T arg) f, T arg);
+
+/// The type of a custom [Zone.runBinary] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The function [f] and values [arg1] and [arg2] are the function and arguments
+/// which was passed to the [Zone.runBinary] of [zone].
+///
+/// The default behavior of [Zone.runUnary] is
+/// to call [f] with arguments [arg1] and [arg2] in the current zone, [zone].
+/// A custom handler can do things before, after or instead of
+/// calling [f].
 typedef RunBinaryHandler = R Function<R, T1, T2>(Zone self, ZoneDelegate parent,
     Zone zone, R Function(T1 arg1, T2 arg2) f, T1 arg1, T2 arg2);
+
+/// The type of a custom [Zone.registerCallback] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The function [f] is the function which was passed to the
+/// [Zone.registerCallback] of [zone].
+///
+/// The handler should return either the function [f]
+/// or another function replacing [f],
+/// typically by wrapping [f] in a function
+/// which does something extra before and after invoking [f]
 typedef RegisterCallbackHandler = ZoneCallback<R> Function<R>(
     Zone self, ZoneDelegate parent, Zone zone, R Function() f);
+
+/// The type of a custom [Zone.registerUnary] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The function [f] is the function which was passed to the
+/// which was passed to the [Zone.registerUnary] of [zone].
+///
+/// The handler should return either the function [f]
+/// or another function replacing [f],
+/// typically by wrapping [f] in a function
+/// which does something extra before and after invoking [f]
 typedef RegisterUnaryCallbackHandler = ZoneUnaryCallback<R, T> Function<R, T>(
     Zone self, ZoneDelegate parent, Zone zone, R Function(T arg) f);
+
+/// The type of a custom [Zone.registerBinary] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The function [f] is the function which was passed to the
+/// which was passed to the [Zone.registerBinary] of [zone].
+///
+/// The handler should return either the function [f]
+/// or another function replacing [f],
+/// typically by wrapping [f] in a function
+/// which does something extra before and after invoking [f]
 typedef RegisterBinaryCallbackHandler
     = ZoneBinaryCallback<R, T1, T2> Function<R, T1, T2>(Zone self,
         ZoneDelegate parent, Zone zone, R Function(T1 arg1, T2 arg2) f);
+
+/// The type of a custom [Zone.errorCallback] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The [error] and [stackTrace] are the error and stack trace
+/// passed to [Zone.errorCallback] of [zone].
+///
+/// The function should return either `null` if it doesn't want
+/// to replace the original error and stack trace,
+/// or an [AsyncError] containg a replacement error and stack trace
+/// which will be used to replace the originals.
 typedef AsyncError? ErrorCallbackHandler(Zone self, ZoneDelegate parent,
     Zone zone, Object error, StackTrace? stackTrace);
+
+/// The type of a custom [Zone.scheduleMicrotask] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The function [f] is the function which was
+/// passed to [Zone.scheduleMicrotask] of [zone].
+///
+/// The custom handler can choose to replace the function [f]
+/// with one that does something before, after or instead of calling [f],
+/// and then call `parent.scheduleMicrotask(zone, replacement)`.
+/// or it can implement its own microtask scheduling queue, which typically
+/// still depends on `parent.scheduleMicrotask` to as a way to get started.
 typedef void ScheduleMicrotaskHandler(
     Zone self, ZoneDelegate parent, Zone zone, void f());
+
+/// The type of a custom [Zone.createTimer] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The callback function [f] and [duration] are the ones which were
+/// passed to [Zone.createTimer] of [zone]
+/// (possibly through the [Timer] constructor).
+///
+/// The custom handler can choose to replace the function [f]
+/// with one that does something before, after or instead of calling [f],
+/// and then call `parent.createTimer(zone, replacement)`.
+/// or it can implement its own timer queue, which typically
+/// still depends on `parent.createTimer` to as a way to get started.
+///
+/// The function should return a [Timer] object which can be used
+/// to inspect and control the scheduled timer callback.
 typedef Timer CreateTimerHandler(
     Zone self, ZoneDelegate parent, Zone zone, Duration duration, void f());
+
+/// The type of a custom [Zone.createPeriodicTimer] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The callback function [f] and [duration] are the ones which were
+/// passed to [Zone.createPeriodicTimer] of [zone]
+/// (possibly through the [Timer.periodic] constructor).
+///
+/// The custom handler can choose to replace the function [f]
+/// with one that does something before, after or instead of calling [f],
+/// and then call `parent.createTimer(zone, replacement)`.
+/// or it can implement its own timer queue, which typically
+/// still depends on `parent.createTimer` to as a way to get started.
+///
+/// The function should return a [Timer] object which can be used
+/// to inspect and control the scheduled timer callbacks.
 typedef Timer CreatePeriodicTimerHandler(Zone self, ZoneDelegate parent,
     Zone zone, Duration period, void f(Timer timer));
+
+/// The type of a custom [Zone.print] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The string [line] is the one which was passed to [Zone.print] of [zone],
+/// (possibly through the global [print] function).
+///
+/// The custom handler can intercept print operations and
+/// redirect them to other targets than the console.
 typedef void PrintHandler(
     Zone self, ZoneDelegate parent, Zone zone, String line);
+
+/// The type of a custom [Zone.fork] implementation function.
+///
+/// Receives the [Zone] that the handler was registered on as [self],
+/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
+/// and the current zone where the error was uncaught as [zone],
+/// which will have [self] as a parent zone.
+///
+/// The handler should create a new zone with [zone] as its
+/// immediate parent zone.
+///
+/// The [specification] and [zoneValues] are the ones which were
+/// passed to [Zone.fork] of [zone]. They specify the custom zone
+/// handlers and zone variables that the new zone should have.
+///
+/// The custom handler can change the specification or zone
+/// values before calling `parent.fork(zone, specification, zoneValues)`,
+/// but it has to call the [parent]'s [ZoneDelegate.fork] in order
+/// to create a valid [Zone] object.
 typedef Zone ForkHandler(Zone self, ZoneDelegate parent, Zone zone,
     ZoneSpecification? specification, Map<Object?, Object?>? zoneValues);
 
-/// Pair of error and stack trace. Returned by [Zone.errorCallback].
-class AsyncError implements Error {
-  final Object error;
-  final StackTrace stackTrace;
-
-  AsyncError(Object error, StackTrace? stackTrace)
-      : error = checkNotNullable(error, "error"),
-        stackTrace = stackTrace ?? defaultStackTrace(error);
-
-  /// A default stack trace for an error.
-  ///
-  /// If [error] is an [Error] and it has an [Error.stackTrace],
-  /// that stack trace is returned.
-  /// If not, the [StackTrace.empty] default stack trace is returned.
-  static StackTrace defaultStackTrace(Object error) {
-    if (error is Error) {
-      var stackTrace = error.stackTrace;
-      if (stackTrace != null) return stackTrace;
-    }
-    return StackTrace.empty;
-  }
-
-  String toString() => '$error';
-}
-
 class _ZoneFunction<T extends Function> {
   final _Zone zone;
   final T function;
@@ -103,29 +280,33 @@
   const _RegisterBinaryZoneFunction(this.zone, this.function);
 }
 
-/**
- * This class provides the specification for a forked zone.
- *
- * When forking a new zone (see [Zone.fork]) one can override the default
- * behavior of the zone by providing callbacks. These callbacks must be
- * given in an instance of this class.
- *
- * Handlers have the same signature as the same-named methods on [Zone] but
- * receive three additional arguments:
- *
- *   1. the zone the handlers are attached to (the "self" zone).
- *   2. a [ZoneDelegate] to the parent zone.
- *   3. the zone that first received the request (before the request was
- *     bubbled up).
- *
- * Handlers can either stop propagation the request (by simply not calling the
- * parent handler), or forward to the parent zone, potentially modifying the
- * arguments on the way.
- */
+/// A parameter object with custom zone function handlers for [Zone.fork].
+///
+/// A zone specification is a parameter object passed to [Zone.fork]
+/// and any underlying [ForkHandler] custom implementations.
+/// The individual handlers, if set to a non-null value,
+/// will be the implementation of the correpsonding [Zone] methods
+/// for a forked zone created using this zone specification.
+///
+/// Handlers have the same signature as the same-named methods on [Zone],
+/// but receive three additional arguments:
+///
+///   1. The zone the handlers are attached to (the "self" zone).
+///      This is the zone created by [Zone.fork] where the handler is
+///      passed as part of the zone delegation.
+///   2. A [ZoneDelegate] to the parent zone.
+///   3. The "current" zone at the time the request was made.
+///      The self zone is always a parent zone of the current zone.
+///
+/// Handlers can either stop propagating the request (by simply not calling the
+/// parent handler), or forward to the parent zone, potentially modifying the
+/// arguments on the way.
 abstract class ZoneSpecification {
-  /**
-   * Creates a specification with the provided handlers.
-   */
+  /// Creates a specification with the provided handlers.
+  ///
+  /// If the [handleUncaughtError] is provided, the new zone will be a new
+  /// "error zone" which will prevent errors from flowing into other
+  /// error zones (see [errorZone], [sameErrorZone]).
   const factory ZoneSpecification(
       {HandleUncaughtErrorHandler? handleUncaughtError,
       RunHandler? run,
@@ -141,10 +322,12 @@
       PrintHandler? print,
       ForkHandler? fork}) = _ZoneSpecification;
 
-  /**
-   * Creates a specification from [other] with the provided handlers overriding
-   * the ones in [other].
-   */
+  /// Creates a specification from [other] and provided handlers.
+  ///
+  /// The created zone specification has the handlers of [other]
+  /// and any individually provided handlers.
+  /// If a handler is provided both through [other] and individually,
+  /// the individually provided handler overries the one from [other].
   factory ZoneSpecification.from(ZoneSpecification other,
       {HandleUncaughtErrorHandler? handleUncaughtError,
       RunHandler? run,
@@ -177,28 +360,51 @@
         fork: fork ?? other.fork);
   }
 
+  /// A custom [Zone.handleUncaughtError] implementation for a new zone.
   HandleUncaughtErrorHandler? get handleUncaughtError;
+
+  /// A custom [Zone.run] implementation for a new zone.
   RunHandler? get run;
+
+  /// A custom [Zone.runUnary] implementation for a new zone.
   RunUnaryHandler? get runUnary;
+
+  /// A custom [Zone.runBinary] implementation for a new zone.
   RunBinaryHandler? get runBinary;
+
+  /// A custom [Zone.registerCallback] implementation for a new zone.
   RegisterCallbackHandler? get registerCallback;
+
+  /// A custom [Zone.registerUnaryCallback] implementation for a new zone.
   RegisterUnaryCallbackHandler? get registerUnaryCallback;
+
+  /// A custom [Zone.registerBinaryCallback] implementation for a new zone.
   RegisterBinaryCallbackHandler? get registerBinaryCallback;
+
+  /// A custom [Zone.errorCallback] implementation for a new zone.
   ErrorCallbackHandler? get errorCallback;
+
+  /// A custom [Zone.scheduleMicrotask] implementation for a new zone.
   ScheduleMicrotaskHandler? get scheduleMicrotask;
+
+  /// A custom [Zone.createTimer] implementation for a new zone.
   CreateTimerHandler? get createTimer;
+
+  /// A custom [Zone.createPeriodicTimer] implementation for a new zone.
   CreatePeriodicTimerHandler? get createPeriodicTimer;
+
+  /// A custom [Zone.print] implementation for a new zone.
   PrintHandler? get print;
+
+  /// A custom [Zone.handleUncaughtError] implementation for a new zone.
   ForkHandler? get fork;
 }
 
-/**
- * Internal [ZoneSpecification] class.
- *
- * The implementation wants to rely on the fact that the getters cannot change
- * dynamically. We thus require users to go through the redirecting
- * [ZoneSpecification] constructor which instantiates this class.
- */
+/// Internal [ZoneSpecification] class.
+///
+/// The implementation wants to rely on the fact that the getters cannot change
+/// dynamically. We thus require users to go through the redirecting
+/// [ZoneSpecification] constructor which instantiates this class.
 class _ZoneSpecification implements ZoneSpecification {
   const _ZoneSpecification(
       {this.handleUncaughtError,
@@ -230,482 +436,452 @@
   final ForkHandler? fork;
 }
 
-/**
- * An adapted view of the parent zone.
- *
- * This class allows the implementation of a zone method to invoke methods on
- * the parent zone while retaining knowledge of the originating zone.
- *
- * Custom zones (created through [Zone.fork] or [runZoned]) can provide
- * implementations of most methods of zones. This is similar to overriding
- * methods on [Zone], except that this mechanism doesn't require subclassing.
- *
- * A custom zone function (provided through a [ZoneSpecification]) typically
- * records or wraps its parameters and then delegates the operation to its
- * parent zone using the provided [ZoneDelegate].
- *
- * While zones have access to their parent zone (through [Zone.parent]) it is
- * recommended to call the methods on the provided parent delegate for two
- * reasons:
- * 1. the delegate methods take an additional `zone` argument which is the
- *   zone the action has been initiated in.
- * 2. delegate calls are more efficient, since the implementation knows how
- *   to skip zones that would just delegate to their parents.
- */
+/// An adapted view of the parent zone.
+///
+/// This class allows the implementation of a zone method to invoke methods on
+/// the parent zone while retaining knowledge of the originating zone.
+///
+/// Custom zones (created through [Zone.fork] or [runZoned]) can provide
+/// implementations of most methods of zones. This is similar to overriding
+/// methods on [Zone], except that this mechanism doesn't require subclassing.
+///
+/// A custom zone function (provided through a [ZoneSpecification]) typically
+/// records or wraps its parameters and then delegates the operation to its
+/// parent zone using the provided [ZoneDelegate].
+///
+/// While zones have access to their parent zone (through [Zone.parent]) it is
+/// recommended to call the methods on the provided parent delegate for two
+/// reasons:
+/// 1. the delegate methods take an additional `zone` argument which is the
+///   zone the action has been initiated in.
+/// 2. delegate calls are more efficient, since the implementation knows how
+///   to skip zones that would just delegate to their parents.
 abstract class ZoneDelegate {
+  // Invoke the [HandleUncaughtErrorHandler] of the zone with a current zone.
   void handleUncaughtError(Zone zone, Object error, StackTrace stackTrace);
+
+  // Invokes the [RunHandler] of the zone with a current zone.
   R run<R>(Zone zone, R f());
+
+  // Invokes the [RunUnaryHandler] of the zone with a current zone.
   R runUnary<R, T>(Zone zone, R f(T arg), T arg);
+
+  // Invokes the [RunBinaryHandler] of the zone with a current zone.
   R runBinary<R, T1, T2>(Zone zone, R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2);
+
+  // Invokes the [RegisterCallbackHandler] of the zone with a current zone.
   ZoneCallback<R> registerCallback<R>(Zone zone, R f());
+
+  // Invokes the [RegisterUnaryHandler] of the zone with a current zone.
   ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(Zone zone, R f(T arg));
+
+  // Invokes the [RegisterBinaryHandler] of the zone with a current zone.
   ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
       Zone zone, R f(T1 arg1, T2 arg2));
+
+  // Invokes the [ErrorCallbackHandler] of the zone with a current zone.
   AsyncError? errorCallback(Zone zone, Object error, StackTrace? stackTrace);
+
+  // Invokes the [ScheduleMicrotaskHandler] of the zone with a current zone.
   void scheduleMicrotask(Zone zone, void f());
+
+  // Invokes the [CreateTimerHandler] of the zone with a current zone.
   Timer createTimer(Zone zone, Duration duration, void f());
+
+  // Invokes the [CreatePeriodicTimerHandler] of the zone with a current zone.
   Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer));
+
+  // Invokes the [PrintHandler] of the zone with a current zone.
   void print(Zone zone, String line);
+
+  // Invokes the [ForkHandler] of the zone with a current zone.
   Zone fork(Zone zone, ZoneSpecification? specification, Map? zoneValues);
 }
 
-/**
- * A zone represents an environment that remains stable across asynchronous
- * calls.
- *
- * Code is always executed in the context of a zone, available as
- * [Zone.current]. The initial `main` function runs in the context of the
- * default zone ([Zone.root]). Code can be run in a different zone using either
- * [runZoned], to create a new zone, or [Zone.run] to run code in the context of
- * an existing zone likely created using [Zone.fork].
- *
- * Developers can create a new zone that overrides some of the functionality of
- * an existing zone. For example, custom zones can replace of modify the
- * behavior of `print`, timers, microtasks or how uncaught errors are handled.
- *
- * The [Zone] class is not subclassable, but users can provide custom zones by
- * forking an existing zone (usually [Zone.current]) with a [ZoneSpecification].
- * This is similar to creating a new class that extends the base `Zone` class
- * and that overrides some methods, except without actually creating a new
- * class. Instead the overriding methods are provided as functions that
- * explicitly take the equivalent of their own class, the "super" class and the
- * `this` object as parameters.
- *
- * Asynchronous callbacks always run in the context of the zone where they were
- * scheduled. This is implemented using two steps:
- * 1. the callback is first registered using one of [registerCallback],
- *   [registerUnaryCallback], or [registerBinaryCallback]. This allows the zone
- *   to record that a callback exists and potentially modify it (by returning a
- *   different callback). The code doing the registration (e.g., `Future.then`)
- *   also remembers the current zone so that it can later run the callback in
- *   that zone.
- * 2. At a later point the registered callback is run in the remembered zone.
- *
- * This is all handled internally by the platform code and most users don't need
- * to worry about it. However, developers of new asynchronous operations,
- * provided by the underlying system or through native extensions, must follow
- * the protocol to be zone compatible.
- *
- * For convenience, zones provide [bindCallback] (and the corresponding
- * [bindUnaryCallback] and [bindBinaryCallback]) to make it easier to respect
- * the zone contract: these functions first invoke the corresponding `register`
- * functions and then wrap the returned function so that it runs in the current
- * zone when it is later asynchronously invoked.
- *
- * Similarly, zones provide [bindCallbackGuarded] (and the corresponding
- * [bindUnaryCallbackGuarded] and [bindBinaryCallbackGuarded]), when the
- * callback should be invoked through [Zone.runGuarded].
- */
+/// A zone represents an environment that remains stable across asynchronous
+/// calls.
+///
+/// Code is always executed in the context of a zone, available as
+/// [Zone.current]. The initial `main` function runs in the context of the
+/// default zone ([Zone.root]). Code can be run in a different zone using either
+/// [runZoned], to create a new zone, or [Zone.run] to run code in the context of
+/// an existing zone which was created earlier using [Zone.fork].
+///
+/// Developers can create a new zone that overrides some of the functionality of
+/// an existing zone. For example, custom zones can replace of modify the
+/// behavior of `print`, timers, microtasks or how uncaught errors are handled.
+///
+/// The [Zone] class is not subclassable, but users can provide custom zones by
+/// forking an existing zone (usually [Zone.current]) with a [ZoneSpecification].
+/// This is similar to creating a new class that extends the base `Zone` class
+/// and that overrides some methods, except without actually creating a new
+/// class. Instead the overriding methods are provided as functions that
+/// explicitly take the equivalent of their own class, the "super" class and the
+/// `this` object as parameters.
+///
+/// Asynchronous callbacks always run in the context of the zone where they were
+/// scheduled. This is implemented using two steps:
+/// 1. the callback is first registered using one of [registerCallback],
+///   [registerUnaryCallback], or [registerBinaryCallback]. This allows the zone
+///   to record that a callback exists and potentially modify it (by returning a
+///   different callback). The code doing the registration (e.g., `Future.then`)
+///   also remembers the current zone so that it can later run the callback in
+///   that zone.
+/// 2. At a later point the registered callback is run in the remembered zone,
+///    using one of [run], [runUnary] or [runBinary].
+///
+/// This is all handled internally by the platform code and most users don't need
+/// to worry about it. However, developers of new asynchronous operations,
+/// provided by the underlying system or through native extensions, must follow
+/// the protocol to be zone compatible.
+///
+/// For convenience, zones provide [bindCallback] (and the corresponding
+/// [bindUnaryCallback] and [bindBinaryCallback]) to make it easier to respect
+/// the zone contract: these functions first invoke the corresponding `register`
+/// functions and then wrap the returned function so that it runs in the current
+/// zone when it is later asynchronously invoked.
+///
+/// Similarly, zones provide [bindCallbackGuarded] (and the corresponding
+/// [bindUnaryCallbackGuarded] and [bindBinaryCallbackGuarded]), when the
+/// callback should be invoked through [Zone.runGuarded].
 abstract class Zone {
   // Private constructor so that it is not possible instantiate a Zone class.
   Zone._();
 
-  /**
-   * The root zone.
-   *
-   * All isolate entry functions (`main` or spawned functions) start running in
-   * the root zone (that is, [Zone.current] is identical to [Zone.root] when the
-   * entry function is called). If no custom zone is created, the rest of the
-   * program always runs in the root zone.
-   *
-   * The root zone implements the default behavior of all zone operations.
-   * Many methods, like [registerCallback] do the bare minimum required of the
-   * function, and are only provided as a hook for custom zones. Others, like
-   * [scheduleMicrotask], interact with the underlying system to implement the
-   * desired behavior.
-   */
+  /// The root zone.
+  ///
+  /// All isolate entry functions (`main` or spawned functions) start running in
+  /// the root zone (that is, [Zone.current] is identical to [Zone.root] when the
+  /// entry function is called). If no custom zone is created, the rest of the
+  /// program always runs in the root zone.
+  ///
+  /// The root zone implements the default behavior of all zone operations.
+  /// Many methods, like [registerCallback] do the bare minimum required of the
+  /// function, and are only provided as a hook for custom zones. Others, like
+  /// [scheduleMicrotask], interact with the underlying system to implement the
+  /// desired behavior.
   static const Zone root = _rootZone;
 
-  /** The currently running zone. */
+  /// The currently running zone.
   static _Zone _current = _rootZone;
 
-  /** The zone that is currently active. */
+  /// The zone that is currently active.
   static Zone get current => _current;
 
-  /**
-   * Handles uncaught asynchronous errors.
-   *
-   * There are two kind of asynchronous errors that are handled by this
-   * function:
-   * 1. Uncaught errors that were thrown in asynchronous callbacks, for example,
-   *   a `throw` in the function passed to [Timer.run].
-   * 2. Asynchronous errors that are pushed through [Future] and [Stream]
-   *   chains, but for which no child registered an error handler.
-   *   Most asynchronous classes, like [Future] or [Stream] push errors to their
-   *   listeners. Errors are propagated this way until either a listener handles
-   *   the error (for example with [Future.catchError]), or no listener is
-   *   available anymore. In the latter case, futures and streams invoke the
-   *   zone's [handleUncaughtError].
-   *
-   * By default, when handled by the root zone, uncaught asynchronous errors are
-   * treated like uncaught synchronous exceptions.
-   */
+  /// Handles uncaught asynchronous errors.
+  ///
+  /// There are two kind of asynchronous errors that are handled by this
+  /// function:
+  /// 1. Uncaught errors that were thrown in asynchronous callbacks, for example,
+  ///   a `throw` in the function passed to [Timer.run].
+  /// 2. Asynchronous errors that are pushed through [Future] and [Stream]
+  ///   chains, but for which nobody registered an error handler.
+  ///   Most asynchronous classes, like [Future] or [Stream] push errors to their
+  ///   listeners. Errors are propagated this way until either a listener handles
+  ///   the error (for example with [Future.catchError]), or no listener is
+  ///   available anymore. In the latter case, futures and streams invoke the
+  ///   zone's [handleUncaughtError].
+  ///
+  /// By default, when handled by the root zone, uncaught asynchronous errors are
+  /// treated like uncaught synchronous exceptions.
   void handleUncaughtError(Object error, StackTrace stackTrace);
 
-  /**
-   * The parent zone of the this zone.
-   *
-   * Is `null` if `this` is the [root] zone.
-   *
-   * Zones are created by [fork] on an existing zone, or by [runZoned] which
-   * forks the [current] zone. The new zone's parent zone is the zone it was
-   * forked from.
-   */
+  /// The parent zone of the this zone.
+  ///
+  /// Is `null` if `this` is the [root] zone.
+  ///
+  /// Zones are created by [fork] on an existing zone, or by [runZoned] which
+  /// forks the [current] zone. The new zone's parent zone is the zone it was
+  /// forked from.
   Zone? get parent;
 
-  /**
-   * The error zone is the one that is responsible for dealing with uncaught
-   * errors.
-   *
-   * This is the closest parent zone of this zone that provides a
-   * [handleUncaughtError] method.
-   *
-   * Asynchronous errors never cross zone boundaries between zones with
-   * different error handlers.
-   *
-   * Example:
-   * ```
-   * import 'dart:async';
-   *
-   * main() {
-   *   var future;
-   *   runZoned(() {
-   *     // The asynchronous error is caught by the custom zone which prints
-   *     // 'asynchronous error'.
-   *     future = Future.error("asynchronous error");
-   *   }, onError: (e) { print(e); });  // Creates a zone with an error handler.
-   *   // The following `catchError` handler is never invoked, because the
-   *   // custom zone created by the call to `runZoned` provides an
-   *   // error handler.
-   *   future.catchError((e) { throw "is never reached"; });
-   * }
-   * ```
-   *
-   * Note that errors cannot enter a child zone with a different error handler
-   * either:
-   * ```
-   * import 'dart:async';
-   *
-   * main() {
-   *   runZoned(() {
-   *     // The following asynchronous error is *not* caught by the `catchError`
-   *     // in the nested zone, since errors are not to cross zone boundaries
-   *     // with different error handlers.
-   *     // Instead the error is handled by the current error handler,
-   *     // printing "Caught by outer zone: asynchronous error".
-   *     var future = Future.error("asynchronous error");
-   *     runZoned(() {
-   *       future.catchError((e) { throw "is never reached"; });
-   *     }, onError: (e) { throw "is never reached"; });
-   *   }, onError: (e) { print("Caught by outer zone: $e"); });
-   * }
-   * ```
-   */
+  /// The error zone is responsible for dealing with uncaught errors.
+  ///
+  /// This is the closest parent zone of this zone that provides a
+  /// [handleUncaughtError] method.
+  ///
+  /// Asynchronous errors never cross zone boundaries between zones with
+  /// different error handlers.
+  ///
+  /// Example:
+  /// ```
+  /// import 'dart:async';
+  ///
+  /// main() {
+  ///   var future;
+  ///   runZoned(() {
+  ///     // The asynchronous error is caught by the custom zone which prints
+  ///     // 'asynchronous error'.
+  ///     future = Future.error("asynchronous error");
+  ///   }, onError: (e) { print(e); });  // Creates a zone with an error handler.
+  ///   // The following `catchError` handler is never invoked, because the
+  ///   // custom zone created by the call to `runZoned` provides an
+  ///   // error handler.
+  ///   future.catchError((e) { throw "is never reached"; });
+  /// }
+  /// ```
+  ///
+  /// Note that errors cannot enter a child zone with a different error handler
+  /// either:
+  /// ```
+  /// import 'dart:async';
+  ///
+  /// main() {
+  ///   runZoned(() {
+  ///     // The following asynchronous error is *not* caught by the `catchError`
+  ///     // in the nested zone, since errors are not to cross zone boundaries
+  ///     // with different error handlers.
+  ///     // Instead the error is handled by the current error handler,
+  ///     // printing "Caught by outer zone: asynchronous error".
+  ///     var future = Future.error("asynchronous error");
+  ///     runZoned(() {
+  ///       future.catchError((e) { throw "is never reached"; });
+  ///     }, onError: (e) { throw "is never reached"; });
+  ///   }, onError: (e) { print("Caught by outer zone: $e"); });
+  /// }
+  /// ```
   Zone get errorZone;
 
-  /**
-   * Returns true if `this` and [otherZone] are in the same error zone.
-   *
-   * Two zones are in the same error zone if they have the same [errorZone].
-   */
+  /// Whether this zone and [otherZone] are in the same error zone.
+  ///
+  /// Two zones are in the same error zone if they have the same [errorZone].
   bool inSameErrorZone(Zone otherZone);
 
-  /**
-   * Creates a new zone as a child of `this`.
-   *
-   * The new zone uses the closures in the given [specification] to override
-   * the current's zone behavior. All specification entries that are `null`
-   * inherit the behavior from the parent zone (`this`).
-   *
-   * The new zone inherits the stored values (accessed through [operator []])
-   * of this zone and updates them with values from [zoneValues], which either
-   * adds new values or overrides existing ones.
-   *
-   * Note that the fork operation is interceptible. A zone can thus change
-   * the zone specification (or zone values), giving the forking zone full
-   * control over the child zone.
-   */
+  /// Creates a new zone as a child zone of this zone.
+  ///
+  /// The new zone uses the closures in the given [specification] to override
+  /// the current's zone behavior. All specification entries that are `null`
+  /// inherit the behavior from the parent zone (`this`).
+  ///
+  /// The new zone inherits the stored values (accessed through [operator []])
+  /// of this zone and updates them with values from [zoneValues], which either
+  /// adds new values or overrides existing ones.
+  ///
+  /// Note that the fork operation is interceptible. A zone can thus change
+  /// the zone specification (or zone values), giving the forking zone full
+  /// control over the child zone.
   Zone fork(
       {ZoneSpecification? specification, Map<Object?, Object?>? zoneValues});
 
-  /**
-   * Executes [action] in this zone.
-   *
-   * By default (as implemented in the [root] zone), runs [action]
-   * with [current] set to this zone.
-   *
-   * If [action] throws, the synchronous exception is not caught by the zone's
-   * error handler. Use [runGuarded] to achieve that.
-   *
-   * Since the root zone is the only zone that can modify the value of
-   * [current], custom zones intercepting run should always delegate to their
-   * parent zone. They may take actions before and after the call.
-   */
+  /// Executes [action] in this zone.
+  ///
+  /// By default (as implemented in the [root] zone), runs [action]
+  /// with [current] set to this zone.
+  ///
+  /// If [action] throws, the synchronous exception is not caught by the zone's
+  /// error handler. Use [runGuarded] to achieve that.
+  ///
+  /// Since the root zone is the only zone that can modify the value of
+  /// [current], custom zones intercepting run should always delegate to their
+  /// parent zone. They may take actions before and after the call.
   R run<R>(R action());
 
-  /**
-   * Executes the given [action] with [argument] in this zone.
-   *
-   * As [run] except that [action] is called with one [argument] instead of
-   * none.
-   */
+  /// Executes the given [action] with [argument] in this zone.
+  ///
+  /// As [run] except that [action] is called with one [argument] instead of
+  /// none.
   R runUnary<R, T>(R action(T argument), T argument);
 
-  /**
-   * Executes the given [action] with [argument1] and [argument2] in this
-   * zone.
-   *
-   * As [run] except that [action] is called with two arguments instead of none.
-   */
+  /// Executes the given [action] with [argument1] and [argument2] in this
+  /// zone.
+  ///
+  /// As [run] except that [action] is called with two arguments instead of none.
   R runBinary<R, T1, T2>(
       R action(T1 argument1, T2 argument2), T1 argument1, T2 argument2);
 
-  /**
-   * Executes the given [action] in this zone and catches synchronous
-   * errors.
-   *
-   * This function is equivalent to:
-   * ```
-   * try {
-   *   this.run(action);
-   * } catch (e, s) {
-   *   this.handleUncaughtError(e, s);
-   * }
-   * ```
-   *
-   * See [run].
-   */
+  /// Executes the given [action] in this zone and catches synchronous
+  /// errors.
+  ///
+  /// This function is equivalent to:
+  /// ```
+  /// try {
+  ///   this.run(action);
+  /// } catch (e, s) {
+  ///   this.handleUncaughtError(e, s);
+  /// }
+  /// ```
+  ///
+  /// See [run].
   void runGuarded(void action());
 
-  /**
-   * Executes the given [action] with [argument] in this zone and
-   * catches synchronous errors.
-   *
-   * See [runGuarded].
-   */
+  /// Executes the given [action] with [argument] in this zone and
+  /// catches synchronous errors.
+  ///
+  /// See [runGuarded].
   void runUnaryGuarded<T>(void action(T argument), T argument);
 
-  /**
-   * Executes the given [action] with [argument1] and [argument2] in this
-   * zone and catches synchronous errors.
-   *
-   * See [runGuarded].
-   */
+  /// Executes the given [action] with [argument1] and [argument2] in this
+  /// zone and catches synchronous errors.
+  ///
+  /// See [runGuarded].
   void runBinaryGuarded<T1, T2>(
       void action(T1 argument1, T2 argument2), T1 argument1, T2 argument2);
 
-  /**
-   * Registers the given callback in this zone.
-   *
-   * When implementing an asynchronous primitive that uses callbacks, the
-   * callback must be registered using [registerCallback] at the point where the
-   * user provides the callback. This allows zones to record other information
-   * that they need at the same time, perhaps even wrapping the callback, so
-   * that the callback is prepared when it is later run in the same zones
-   * (using [run]). For example, a zone may decide
-   * to store the stack trace (at the time of the registration) with the
-   * callback.
-   *
-   * Returns the callback that should be used in place of the provided
-   * [callback]. Frequently zones simply return the original callback.
-   *
-   * Custom zones may intercept this operation. The default implementation in
-   * [Zone.root] returns the original callback unchanged.
-   */
+  /// Registers the given callback in this zone.
+  ///
+  /// When implementing an asynchronous primitive that uses callbacks, the
+  /// callback must be registered using [registerCallback] at the point where the
+  /// user provides the callback. This allows zones to record other information
+  /// that they need at the same time, perhaps even wrapping the callback, so
+  /// that the callback is prepared when it is later run in the same zones
+  /// (using [run]). For example, a zone may decide
+  /// to store the stack trace (at the time of the registration) with the
+  /// callback.
+  ///
+  /// Returns the callback that should be used in place of the provided
+  /// [callback]. Frequently zones simply return the original callback.
+  ///
+  /// Custom zones may intercept this operation. The default implementation in
+  /// [Zone.root] returns the original callback unchanged.
   ZoneCallback<R> registerCallback<R>(R callback());
 
-  /**
-   * Registers the given callback in this zone.
-   *
-   * Similar to [registerCallback] but with a unary callback.
-   */
+  /// Registers the given callback in this zone.
+  ///
+  /// Similar to [registerCallback] but with a unary callback.
   ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(R callback(T arg));
 
-  /**
-   * Registers the given callback in this zone.
-   *
-   * Similar to [registerCallback] but with a unary callback.
-   */
+  /// Registers the given callback in this zone.
+  ///
+  /// Similar to [registerCallback] but with a unary callback.
   ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
       R callback(T1 arg1, T2 arg2));
 
-  /**
-   *  Registers the provided [callback] and returns a function that will
-   *  execute in this zone.
-   *
-   *  Equivalent to:
-   *
-   *      ZoneCallback registered = this.registerCallback(callback);
-   *      return () => this.run(registered);
-   *
-   */
+  /// Registers the provided [callback] and returns a function that will
+  /// execute in this zone.
+  ///
+  /// Equivalent to:
+  /// ```dart
+  /// ZoneCallback registered = this.registerCallback(callback);
+  /// return () => this.run(registered);
+  /// ```
   ZoneCallback<R> bindCallback<R>(R callback());
 
-  /**
-   *  Registers the provided [callback] and returns a function that will
-   *  execute in this zone.
-   *
-   *  Equivalent to:
-   *
-   *      ZoneCallback registered = this.registerUnaryCallback(callback);
-   *      return (arg) => thin.runUnary(registered, arg);
-   */
+  /// Registers the provided [callback] and returns a function that will
+  /// execute in this zone.
+  ///
+  /// Equivalent to:
+  /// ```dart
+  /// ZoneCallback registered = this.registerUnaryCallback(callback);
+  /// return (arg) => thin.runUnary(registered, arg);
+  /// ```
   ZoneUnaryCallback<R, T> bindUnaryCallback<R, T>(R callback(T argument));
 
-  /**
-   *  Registers the provided [callback] and returns a function that will
-   *  execute in this zone.
-   *
-   *  Equivalent to:
-   *
-   *      ZoneCallback registered = registerBinaryCallback(callback);
-   *      return (arg1, arg2) => thin.runBinary(registered, arg1, arg2);
-   */
+  /// Registers the provided [callback] and returns a function that will
+  /// execute in this zone.
+  ///
+  /// Equivalent to:
+  /// ```dart
+  /// ZoneCallback registered = registerBinaryCallback(callback);
+  /// return (arg1, arg2) => thin.runBinary(registered, arg1, arg2);
+  /// ```
   ZoneBinaryCallback<R, T1, T2> bindBinaryCallback<R, T1, T2>(
       R callback(T1 argument1, T2 argument2));
 
-  /**
-   * Registers the provided [callback] and returns a function that will
-   * execute in this zone.
-   *
-   * When the function executes, errors are caught and treated as uncaught
-   * errors.
-   *
-   * Equivalent to:
-   *
-   *     ZoneCallback registered = this.registerCallback(callback);
-   *     return () => this.runGuarded(registered);
-   *
-   */
+  /// Registers the provided [callback] and returns a function that will
+  /// execute in this zone.
+  ///
+  /// When the function executes, errors are caught and treated as uncaught
+  /// errors.
+  ///
+  /// Equivalent to:
+  /// ```dart
+  /// ZoneCallback registered = this.registerCallback(callback);
+  /// return () => this.runGuarded(registered);
+  /// ```
   void Function() bindCallbackGuarded(void Function() callback);
 
-  /**
-   * Registers the provided [callback] and returns a function that will
-   * execute in this zone.
-   *
-   * When the function executes, errors are caught and treated as uncaught
-   * errors.
-   *
-   * Equivalent to:
-   *
-   *     ZoneCallback registered = this.registerUnaryCallback(callback);
-   *     return (arg) => this.runUnaryGuarded(registered, arg);
-   */
+  /// Registers the provided [callback] and returns a function that will
+  /// execute in this zone.
+  ///
+  /// When the function executes, errors are caught and treated as uncaught
+  /// errors.
+  ///
+  /// Equivalent to:
+  /// ```dart
+  /// ZoneCallback registered = this.registerUnaryCallback(callback);
+  /// return (arg) => this.runUnaryGuarded(registered, arg);
+  /// ```
   void Function(T) bindUnaryCallbackGuarded<T>(void callback(T argument));
 
-  /**
-   *  Registers the provided [callback] and returns a function that will
-   *  execute in this zone.
-   *
-   *  Equivalent to:
-   *
-   *      ZoneCallback registered = registerBinaryCallback(callback);
-   *      return (arg1, arg2) => this.runBinaryGuarded(registered, arg1, arg2);
-   */
+  ///  Registers the provided [callback] and returns a function that will
+  ///  execute in this zone.
+  ///
+  ///  Equivalent to:
+  /// ```dart
+  ///  ZoneCallback registered = registerBinaryCallback(callback);
+  ///  return (arg1, arg2) => this.runBinaryGuarded(registered, arg1, arg2);
+  /// ```
   void Function(T1, T2) bindBinaryCallbackGuarded<T1, T2>(
       void callback(T1 argument1, T2 argument2));
 
-  /**
-   * Intercepts errors when added programmatically to a `Future` or `Stream`.
-   *
-   * When calling [Completer.completeError], [StreamController.addError],
-   * or some [Future] constructors, the current zone is allowed to intercept
-   * and replace the error.
-   *
-   * Future constructors invoke this function when the error is received
-   * directly, for example with [Future.error], or when the error is caught
-   * synchronously, for example with [Future.sync].
-   *
-   * There is no guarantee that an error is only sent through [errorCallback]
-   * once. Libraries that use intermediate controllers or completers might
-   * end up invoking [errorCallback] multiple times.
-   *
-   * Returns `null` if no replacement is desired. Otherwise returns an instance
-   * of [AsyncError] holding the new pair of error and stack trace.
-   *
-   * Although not recommended, the returned instance may have its `error` member
-   * ([AsyncError.error]) be equal to `null` in which case the error should be
-   * replaced by a [NullThrownError].
-   *
-   * Custom zones may intercept this operation.
-   *
-   * Implementations of a new asynchronous primitive that converts synchronous
-   * errors to asynchronous errors rarely need to invoke [errorCallback], since
-   * errors are usually reported through future completers or stream
-   * controllers.
-   */
+  /// Intercepts errors when added programmatically to a [Future] or [Stream].
+  ///
+  /// When calling [Completer.completeError], [StreamController.addError],
+  /// or some [Future] constructors, the current zone is allowed to intercept
+  /// and replace the error.
+  ///
+  /// Future constructors invoke this function when the error is received
+  /// directly, for example with [Future.error], or when the error is caught
+  /// synchronously, for example with [Future.sync].
+  ///
+  /// There is no guarantee that an error is only sent through [errorCallback]
+  /// once. Libraries that use intermediate controllers or completers might
+  /// end up invoking [errorCallback] multiple times.
+  ///
+  /// Returns `null` if no replacement is desired. Otherwise returns an instance
+  /// of [AsyncError] holding the new pair of error and stack trace.
+  ///
+  /// Custom zones may intercept this operation.
+  ///
+  /// Implementations of a new asynchronous primitive that converts synchronous
+  /// errors to asynchronous errors rarely need to invoke [errorCallback], since
+  /// errors are usually reported through future completers or stream
+  /// controllers.
   AsyncError? errorCallback(Object error, StackTrace? stackTrace);
 
-  /**
-   * Runs [callback] asynchronously in this zone.
-   *
-   * The global `scheduleMicrotask` delegates to the current zone's
-   * [scheduleMicrotask]. The root zone's implementation interacts with the
-   * underlying system to schedule the given callback as a microtask.
-   *
-   * Custom zones may intercept this operation (for example to wrap the given
-   * [callback]).
-   */
+  /// Runs [callback] asynchronously in this zone.
+  ///
+  /// The global `scheduleMicrotask` delegates to the [current] zone's
+  /// [scheduleMicrotask]. The root zone's implementation interacts with the
+  /// underlying system to schedule the given callback as a microtask.
+  ///
+  /// Custom zones may intercept this operation (for example to wrap the given
+  /// [callback]), or to implement their own microtask scheduler.
+  /// In the latter case, they will usually still use the parent zone's
+  /// [ZoneDelegate.scheduleMicrotask] to attach themselves to the existing
+  /// event loop.
   void scheduleMicrotask(void Function() callback);
 
-  /**
-   * Creates a Timer where the callback is executed in this zone.
-   */
+  /// Creates a [Timer] where the callback is executed in this zone.
   Timer createTimer(Duration duration, void Function() callback);
 
-  /**
-   * Creates a periodic Timer where the callback is executed in this zone.
-   */
+  /// Creates a periodic [Timer] where the callback is executed in this zone.
   Timer createPeriodicTimer(Duration period, void callback(Timer timer));
 
-  /**
-   * Prints the given [line].
-   *
-   * The global `print` function delegates to the current zone's [print]
-   * function which makes it possible to intercept printing.
-   *
-   * Example:
-   * ```
-   * import 'dart:async';
-   *
-   * main() {
-   *   runZoned(() {
-   *     // Ends up printing: "Intercepted: in zone".
-   *     print("in zone");
-   *   }, zoneSpecification: new ZoneSpecification(
-   *       print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
-   *     parent.print(zone, "Intercepted: $line");
-   *   }));
-   * }
-   * ```
-   */
+  /// Prints the given [line].
+  ///
+  /// The global `print` function delegates to the current zone's [print]
+  /// function which makes it possible to intercept printing.
+  ///
+  /// Example:
+  /// ```
+  /// import 'dart:async';
+  ///
+  /// main() {
+  ///   runZoned(() {
+  ///     // Ends up printing: "Intercepted: in zone".
+  ///     print("in zone");
+  ///   }, zoneSpecification: new ZoneSpecification(
+  ///       print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
+  ///     parent.print(zone, "Intercepted: $line");
+  ///   }));
+  /// }
+  /// ```
   void print(String line);
 
-  /**
-   * Call to enter the Zone.
-   *
-   * The previous current zone is returned.
-   */
+  /// Call to enter the [Zone].
+  ///
+  /// The previous current zone is returned.
   static _Zone _enter(_Zone zone) {
     assert(!identical(zone, _current));
     _Zone previous = _current;
@@ -713,27 +889,23 @@
     return previous;
   }
 
-  /**
-   * Call to leave the Zone.
-   *
-   * The previous Zone must be provided as `previous`.
-   */
+  /// Call to leave the [Zone].
+  ///
+  /// The previous [Zone] must be provided as `previous`.
   static void _leave(_Zone previous) {
     assert(previous != null);
     Zone._current = previous;
   }
 
-  /**
-   * Retrieves the zone-value associated with [key].
-   *
-   * If this zone does not contain the value looks up the same key in the
-   * parent zone. If the [key] is not found returns `null`.
-   *
-   * Any object can be used as key, as long as it has compatible `operator ==`
-   * and `hashCode` implementations.
-   * By controlling access to the key, a zone can grant or deny access to the
-   * zone value.
-   */
+  /// Retrieves the zone-value associated with [key].
+  ///
+  /// If this zone does not contain the value looks up the same key in the
+  /// parent zone. If the [key] is not found returns `null`.
+  ///
+  /// Any object can be used as key, as long as it has compatible `operator ==`
+  /// and `hashCode` implementations.
+  /// By controlling access to the key, a zone can grant or deny access to the
+  /// zone value.
   dynamic operator [](Object? key);
 }
 
@@ -839,9 +1011,7 @@
   }
 }
 
-/**
- * Base class for Zone implementations.
- */
+/// Base class for Zone implementations.
 abstract class _Zone implements Zone {
   const _Zone();
 
@@ -981,12 +1151,10 @@
     }
   }
 
-  /**
-   * The closest error-handling zone.
-   *
-   * Returns `this` if `this` has an error-handler. Otherwise returns the
-   * parent's error-zone.
-   */
+  /// The closest error-handling zone.
+  ///
+  /// Returns this zone if it has an error-handler. Otherwise returns the
+  /// parent's error-zone.
   Zone get errorZone => _handleUncaughtError.zone;
 
   void runGuarded(void f()) {
@@ -1352,12 +1520,10 @@
   // It's a lie, but the root zone never uses the parent delegate.
   ZoneDelegate get _parentDelegate => _delegate;
 
-  /**
-   * The closest error-handling zone.
-   *
-   * Returns `this` if `this` has an error-handler. Otherwise returns the
-   * parent's error-zone.
-   */
+  /// The closest error-handling zone.
+  ///
+  /// Returns `this` if `this` has an error-handler. Otherwise returns the
+  /// parent's error-zone.
   Zone get errorZone => this;
 
   // Zone interface.
@@ -1481,49 +1647,47 @@
 
 const _Zone _rootZone = const _RootZone();
 
-/**
- * Runs [body] in its own zone.
- *
- * Creates a new zone using [Zone.fork] based on [zoneSpecification] and
- * [zoneValues], then runs [body] in that zone and returns the result.
- *
- * If [onError] is provided, it must have one of the types
- * * `void Function(Object)`
- * * `void Function(Object, StackTrace)`
- * and the [onError] handler is used *both* to handle asynchronous errors
- * by overriding [ZoneSpecification.handleUncaughtError] in [zoneSpecification],
- * if any, *and* to handle errors thrown synchronously by the call to [body].
- *
- * If an error occurs synchronously in [body],
- * then throwing in the [onError] handler
- * makes the call to `runZone` throw that error,
- * and otherwise the call to `runZoned` attempt to return `null`.
- *
- * If the zone specification has a `handleUncaughtError` value or the [onError]
- * parameter is provided, the zone becomes an error-zone.
- *
- * Errors will never cross error-zone boundaries by themselves.
- * Errors that try to cross error-zone boundaries are considered uncaught in
- * their originating error zone.
- *
- *     var future = new Future.value(499);
- *     runZoned(() {
- *       var future2 = future.then((_) { throw "error in first error-zone"; });
- *       runZoned(() {
- *         var future3 = future2.catchError((e) { print("Never reached!"); });
- *       }, onError: (e, s) { print("unused error handler"); });
- *     }, onError: (e, s) { print("catches error of first error-zone."); });
- *
- * Example:
- *
- *     runZoned(() {
- *       new Future(() { throw "asynchronous error"; });
- *     }, onError: (e, s) => print(e));  // Will print "asynchronous error".
- *
- * It is possible to manually pass an error from one error zone to another
- * by re-throwing it in the new zone. If [onError] throws, that error will
- * occur in the original zone where [runZoned] was called.
- */
+/// Runs [body] in its own zone.
+///
+/// Creates a new zone using [Zone.fork] based on [zoneSpecification] and
+/// [zoneValues], then runs [body] in that zone and returns the result.
+///
+/// If [onError] is provided, it must have one of the types
+/// * `void Function(Object)`
+/// * `void Function(Object, StackTrace)`
+/// and the [onError] handler is used *both* to handle asynchronous errors
+/// by overriding [ZoneSpecification.handleUncaughtError] in [zoneSpecification],
+/// if any, *and* to handle errors thrown synchronously by the call to [body].
+///
+/// If an error occurs synchronously in [body],
+/// then throwing in the [onError] handler
+/// makes the call to `runZone` throw that error,
+/// and otherwise the call to `runZoned` attempt to return `null`.
+///
+/// If the zone specification has a `handleUncaughtError` value or the [onError]
+/// parameter is provided, the zone becomes an error-zone.
+///
+/// Errors will never cross error-zone boundaries by themselves.
+/// Errors that try to cross error-zone boundaries are considered uncaught in
+/// their originating error zone.
+/// ```dart
+/// var future = Future.value(499);
+/// runZoned(() {
+///   var future2 = future.then((_) { throw "error in first error-zone"; });
+///   runZoned(() {
+///     var future3 = future2.catchError((e) { print("Never reached!"); });
+///   }, onError: (e, s) { print("unused error handler"); });
+/// }, onError: (e, s) { print("catches error of first error-zone."); });
+/// ```
+/// Example:
+/// ```dart
+/// runZoned(() {
+///   Future(() { throw "asynchronous error"; });
+/// }, onError: (e, s) => print(e));  // Will print "asynchronous error".
+/// ```
+/// It is possible to manually pass an error from one error zone to another
+/// by re-throwing it in the new zone. If [onError] throws, that error will
+/// occur in the original zone where [runZoned] was called.
 R runZoned<R>(R body(),
     {Map<Object?, Object?>? zoneValues,
     ZoneSpecification? zoneSpecification,
@@ -1546,45 +1710,43 @@
   return _runZoned<R>(body, zoneValues, zoneSpecification);
 }
 
-/**
- * Runs [body] in its own error zone.
- *
- * Creates a new zone using [Zone.fork] based on [zoneSpecification] and
- * [zoneValues], then runs [body] in that zone and returns the result.
- *
- * The [onError] function is used *both* to handle asynchronous errors
- * by overriding [ZoneSpecification.handleUncaughtError] in [zoneSpecification],
- * if any, *and* to handle errors thrown synchronously by the call to [body].
- *
- * If an error occurs synchronously in [body],
- * then throwing in the [onError] handler
- * makes the call to `runZonedGuarded` throw that error,
- * and otherwise the call to `runZonedGuarded` returns `null`.
- *
- * The zone will always be an error-zone.
- *
- * Errors will never cross error-zone boundaries by themselves.
- * Errors that try to cross error-zone boundaries are considered uncaught in
- * their originating error zone.
- * ```dart
- * var future = Future.value(499);
- * runZonedGuarded(() {
- *   var future2 = future.then((_) { throw "error in first error-zone"; });
- *   runZonedGuarded(() {
- *     var future3 = future2.catchError((e) { print("Never reached!"); });
- *   }, (e, s) { print("unused error handler"); });
- * }, (e, s) { print("catches error of first error-zone."); });
- * ```
- * Example:
- * ```dart
- * runZonedGuarded(() {
- *   new Future(() { throw "asynchronous error"; });
- * }, (e, s) => print(e));  // Will print "asynchronous error".
- * ```
- * It is possible to manually pass an error from one error zone to another
- * by re-throwing it in the new zone. If [onError] throws, that error will
- * occur in the original zone where [runZoned] was called.
- */
+/// Runs [body] in its own error zone.
+///
+/// Creates a new zone using [Zone.fork] based on [zoneSpecification] and
+/// [zoneValues], then runs [body] in that zone and returns the result.
+///
+/// The [onError] function is used *both* to handle asynchronous errors
+/// by overriding [ZoneSpecification.handleUncaughtError] in [zoneSpecification],
+/// if any, *and* to handle errors thrown synchronously by the call to [body].
+///
+/// If an error occurs synchronously in [body],
+/// then throwing in the [onError] handler
+/// makes the call to `runZonedGuarded` throw that error,
+/// and otherwise the call to `runZonedGuarded` returns `null`.
+///
+/// The zone will always be an error-zone.
+///
+/// Errors will never cross error-zone boundaries by themselves.
+/// Errors that try to cross error-zone boundaries are considered uncaught in
+/// their originating error zone.
+/// ```dart
+/// var future = Future.value(499);
+/// runZonedGuarded(() {
+///   var future2 = future.then((_) { throw "error in first error-zone"; });
+///   runZonedGuarded(() {
+///     var future3 = future2.catchError((e) { print("Never reached!"); });
+///   }, (e, s) { print("unused error handler"); });
+/// }, (e, s) { print("catches error of first error-zone."); });
+/// ```
+/// Example:
+/// ```dart
+/// runZonedGuarded(() {
+///   Future(() { throw "asynchronous error"; });
+/// }, (e, s) => print(e));  // Will print "asynchronous error".
+/// ```
+/// It is possible to manually pass an error from one error zone to another
+/// by re-throwing it in the new zone. If [onError] throws, that error will
+/// occur in the original zone where [runZoned] was called.
 @Since("2.8")
 R? runZonedGuarded<R>(R body(), void onError(Object error, StackTrace stack),
     {Map<Object?, Object?>? zoneValues, ZoneSpecification? zoneSpecification}) {
diff --git a/sdk/lib/core/duration.dart b/sdk/lib/core/duration.dart
index facbcdf..57075cb 100644
--- a/sdk/lib/core/duration.dart
+++ b/sdk/lib/core/duration.dart
@@ -55,12 +55,22 @@
   static const int millisecondsPerSecond = 1000;
 
   /// The number of seconds per minute.
+  ///
+  /// Notice that some minutes of official clock time might
+  /// differ in length because of leap seconds.
+  /// The [Duration] and [DateTime] classes ignore leap seconds
+  /// and consider all minutes to have 60 seconds.
   static const int secondsPerMinute = 60;
 
   /// The number of minutes per hour.
   static const int minutesPerHour = 60;
 
   /// The number of hours per day.
+  ///
+  /// Notice that some days may differ in length because
+  /// of time zone changes due to daylight saving.
+  /// The [Duration] class is time zone agnostic and
+  /// considers all days to have 24 hours.
   static const int hoursPerDay = 24;
 
   /// The number of microseconds per second.
diff --git a/tools/VERSION b/tools/VERSION
index 5fccaeb..f98a1fa 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 224
+PRERELEASE 225
 PRERELEASE_PATCH 0
\ No newline at end of file