Version 2.12.0-253.0.dev

Merge commit '90f3de0421c2d1eae33d6221f355baf6a0e56da2' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 86c7101..b958615 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -69,6 +69,25 @@
 
 [#42312]: https://github.com/dart-lang/sdk/issues/42312
 
+### Foreign Function Interface (`dart:ffi`)
+
+*   **Breaking Change** [#44621][]: Invocations with a generic `T` of
+    `sizeOf<T>`, `Pointer<T>.elementAt()`, `Pointer<T extends Struct>.ref`, and
+    `Pointer<T extends Struct>[]` are being deprecated in the current stable
+    release (2.12), and are planned to be fully removed in the following stable
+    release (2.13). Consequently, `allocate` in `package:ffi` will no longer be
+    able to invoke `sizeOf<T>` generically, and will be deprecated as well.
+    Instead, the `Allocator` it is introduced to `dart:ffi`, and also requires
+    a constant `T` on invocations. For migration notes see the breaking change
+    request.
+*   **Breaking Change** [#44622][]: Subtypes of `Struct` without any native
+    member are being deprecated in the current stable release (2.12), and are
+    planned to be fully removed in the following stable release (2.13).
+    Migrate opaque types to extend `Opaque` rather than `Struct`.
+
+[#44621]: https://github.com/dart-lang/sdk/issues/44621
+[#44622]: https://github.com/dart-lang/sdk/issues/44622
+
 ### Dart2JS
 
 * Removed `--no-defer-class-types` and `--no-new-deferred-split`.
@@ -162,6 +181,9 @@
   dependencies are allowed.
 * New option `dart pub outdated --mode=null-safety` that will analyze your
   dependencies for null-safety.
+* `dart pub get` and `dart pub upgrade` will highlight dependencies that have
+  been [discontinued](https://dart.dev/tools/pub/publishing#discontinue) on
+  pub.dev.
 * `dart pub publish` will now check your pubspec keys for likely typos.
 * `dart pub upgrade package_foo` will fetch dependencies, but ignore the
   `pubspec.lock` for `package_foo`, allowing users to only upgrade a subset of
diff --git a/DEPS b/DEPS
index f867cb4..711f1b5 100644
--- a/DEPS
+++ b/DEPS
@@ -102,7 +102,7 @@
 
   "chromedriver_tag": "83.0.4103.39",
   "dartdoc_rev" : "9e61a4f11091aaa8998525a2692b14148dc24ab5",
-  "ffi_rev": "31352979f261f7c6ea88fa0a2cfb0fdd004c38fb",
+  "ffi_rev": "f288e906c92e2ab378768dfa61a40814ede7a2a5",
   "fixnum_rev": "16d3890c6dc82ca629659da1934e412292508bba",
   "file_rev": "0e09370f581ab6388d46fda4cdab66638c0171a1",
   "glob_rev": "7c0ef8d4fa086f6b185c4dd724b700e7d7ad8f79",
@@ -133,7 +133,7 @@
   "ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
   "pool_rev": "7abe634002a1ba8a0928eded086062f1307ccfae",
   "protobuf_rev": "0d03fd588df69e9863e2a2efc0059dee8f18d5b2",
-  "pub_rev": "392a3cb455af48f7ce8807a96174691945f97f0a",
+  "pub_rev": "7cff05f2522d5468648f854695ca8671aae2104d",
   "pub_semver_rev": "10569a1e867e909cf5db201f73118020453e5db8",
   "resource_rev": "6b79867d0becf5395e5819a75720963b8298e9a7",
   "root_certificates_rev": "7e5ec82c99677a2e5b95ce296c4d68b0d3378ed8",
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 6dbb243..ba1e3a6 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -3745,6 +3745,32 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
+            name)> templateFfiEmptyStructWarning = const Template<
+        Message Function(String name)>(
+    messageTemplate:
+        r"""Struct '#name' is empty. Support for empty structs is deprecated and will be removed in the next stable version of Dart. Use Opaque instead.""",
+    withArguments: _withArgumentsFfiEmptyStructWarning);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)> codeFfiEmptyStructWarning =
+    const Code<Message Function(String name)>("FfiEmptyStructWarning",
+        analyzerCodes: <String>["EMPTY_STRUCT_WARNING"],
+        severity: Severity.info);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFfiEmptyStructWarning(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeFfiEmptyStructWarning,
+      message:
+          """Struct '${name}' is empty. Support for empty structs is deprecated and will be removed in the next stable version of Dart. Use Opaque instead.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeFfiExceptionalReturnNull = messageFfiExceptionalReturnNull;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/_fe_analyzer_shared/test/constants/data/type_literals.dart b/pkg/_fe_analyzer_shared/test/constants/data/type_literals.dart
index f3f9390..3a0c909 100644
--- a/pkg/_fe_analyzer_shared/test/constants/data/type_literals.dart
+++ b/pkg/_fe_analyzer_shared/test/constants/data/type_literals.dart
@@ -18,7 +18,7 @@
     /*cfe.TypeLiteral(void Function<T>(T))*/ GenericFunctionTypedef;
 const typedefWithFutureOr =
     /*cfe.TypeLiteral(void Function<T>(FutureOr<T>))*/ TypedefWithFutureOr;
-const futureOr = /*cfe.TypeLiteral(FutureOr<dynamic>)*/ FutureOr;
+const futureOr = /*cfe.TypeLiteral(dynamic)*/ FutureOr;
 const null_ = /*cfe.TypeLiteral(Null)*/ Null;
 
 main() {
@@ -48,8 +48,7 @@
 
   print(
       /*analyzer.TypeLiteral(FutureOr<dynamic>*)*/
-      /*cfe.TypeLiteral(FutureOr<dynamic>)*/
-      /*dart2js.TypeLiteral(dynamic)*/
+      /*cfe|dart2js.TypeLiteral(dynamic)*/
       futureOr);
 
   print(
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 562c83d..6130688 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -459,6 +459,7 @@
   CompileTimeErrorCode.YIELD_OF_INVALID_TYPE,
   FfiCode.ANNOTATION_ON_POINTER_FIELD,
   FfiCode.EMPTY_STRUCT,
+  FfiCode.EMPTY_STRUCT_WARNING,
   FfiCode.EXTRA_ANNOTATION_ON_STRUCT_FIELD,
   FfiCode.FIELD_IN_STRUCT_WITH_INITIALIZER,
   FfiCode.FIELD_INITIALIZER_IN_STRUCT,
@@ -472,6 +473,7 @@
   FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE,
   FfiCode.MUST_BE_A_SUBTYPE,
   FfiCode.NON_CONSTANT_TYPE_ARGUMENT,
+  FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING,
   FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER,
   FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS,
   FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS,
diff --git a/pkg/analyzer/lib/src/dart/error/ffi_code.dart b/pkg/analyzer/lib/src/dart/error/ffi_code.dart
index 41fa904..63e796e 100644
--- a/pkg/analyzer/lib/src/dart/error/ffi_code.dart
+++ b/pkg/analyzer/lib/src/dart/error/ffi_code.dart
@@ -32,6 +32,17 @@
       correction: "Try adding a field to '{0}' or use a different Struct.");
 
   /**
+   * Parameters:
+   * 0: the name of the struct class
+   */
+  static const FfiCode EMPTY_STRUCT_WARNING = FfiCode(
+      name: 'EMPTY_STRUCT_WARNING',
+      message:
+          "Struct '{0}' is empty. Support for empty structs is deprecated and will be removed in the next stable version of Dart. Use Opaque instead.",
+      correction: "Try adding a field to '{0}' or use a different Struct.",
+      type: ErrorType.HINT);
+
+  /**
    * No parameters.
    */
   static const FfiCode EXTRA_ANNOTATION_ON_STRUCT_FIELD = FfiCode(
@@ -168,6 +179,20 @@
 
   /**
    * Parameters:
+   * 0: the name of the function, method, or constructor having type arguments
+   */
+  static const FfiCode NON_CONSTANT_TYPE_ARGUMENT_WARNING = FfiCode(
+      name: 'NON_CONSTANT_TYPE_ARGUMENT_WARNING',
+      message:
+          "Support for using non-constant type arguments '{0}' in this FFI API"
+          " is deprecated and will be removed in the next stable version of "
+          "Dart. Rewrite the code to ensure that type arguments are compile "
+          "time constants referring to a valid native type.",
+      correction: "Try changing the type argument to be a constant type.",
+      type: ErrorType.HINT);
+
+  /**
+   * Parameters:
    * 0: the type that should be a valid dart:ffi native type.
    */
   static const FfiCode NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER = FfiCode(
@@ -252,6 +277,9 @@
     uniqueName: 'SUBTYPE_OF_STRUCT_CLASS_IN_WITH',
   );
 
+  @override
+  final ErrorType type;
+
   /// Initialize a newly created error code to have the given [name]. If
   /// [uniqueName] is provided, then it will be used to construct the unique
   /// name for the code, otherwise the name will be used to construct the unique
@@ -268,7 +296,9 @@
     @required String message,
     @required String name,
     String uniqueName,
-  }) : super(
+    ErrorType type = ErrorType.COMPILE_TIME_ERROR,
+  })  : type = type,
+        super(
           correction: correction,
           hasPublishedDocs: hasPublishedDocs,
           message: message,
@@ -278,7 +308,4 @@
 
   @override
   ErrorSeverity get errorSeverity => type.severity;
-
-  @override
-  ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
 }
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index aa2140b..8cc04cf 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -63,6 +63,10 @@
         final className = superclass.name.staticElement.name;
         if (className == _structClassName) {
           inStruct = true;
+          if (_isEmptyStruct(node.declaredElement)) {
+            _errorReporter.reportErrorForNode(
+                FfiCode.EMPTY_STRUCT_WARNING, node, [node.name]);
+          }
         } else if (className != _allocatorClassName &&
             className != _opaqueClassName) {
           _errorReporter.reportErrorForNode(
@@ -149,6 +153,19 @@
   }
 
   @override
+  void visitIndexExpression(IndexExpression node) {
+    Element element = node.staticElement;
+    Element enclosingElement = element?.enclosingElement;
+    if (enclosingElement is ExtensionElement) {
+      if (_isNativeStructPointerExtension(enclosingElement)) {
+        if (element.name == '[]') {
+          _validateRefIndexed(node);
+        }
+      }
+    }
+  }
+
+  @override
   void visitMethodInvocation(MethodInvocation node) {
     Element element = node.methodName.staticElement;
     if (element is MethodElement) {
@@ -157,6 +174,8 @@
         if (_isPointer(enclosingElement)) {
           if (element.name == 'fromFunction') {
             _validateFromFunction(node, element);
+          } else if (element.name == 'elementAt') {
+            _validateElementAt(node);
           }
         }
       }
@@ -170,10 +189,47 @@
           _validateLookupFunction(node);
         }
       }
+    } else if (element is FunctionElement) {
+      Element enclosingElement = element.enclosingElement;
+      if (enclosingElement is CompilationUnitElement) {
+        if (element.library.name == 'dart.ffi') {
+          if (element.name == 'sizeOf') {
+            _validateSizeOf(node);
+          }
+        }
+      }
     }
     super.visitMethodInvocation(node);
   }
 
+  @override
+  void visitPrefixedIdentifier(PrefixedIdentifier node) {
+    Element element = node.staticElement;
+    Element enclosingElement = element?.enclosingElement;
+    if (enclosingElement is ExtensionElement) {
+      if (_isNativeStructPointerExtension(enclosingElement)) {
+        if (element.name == 'ref') {
+          _validateRefPrefixedIdentifier(node);
+        }
+      }
+    }
+    super.visitPrefixedIdentifier(node);
+  }
+
+  @override
+  void visitPropertyAccess(PropertyAccess node) {
+    Element element = node.propertyName.staticElement;
+    Element enclosingElement = element?.enclosingElement;
+    if (enclosingElement is ExtensionElement) {
+      if (_isNativeStructPointerExtension(enclosingElement)) {
+        if (element.name == 'ref') {
+          _validateRefPropertyAccess(node);
+        }
+      }
+    }
+    super.visitPropertyAccess(node);
+  }
+
   /// Return `true` if the given [element] represents the extension
   /// `AllocatorAlloc`.
   bool _isAllocatorExtension(Element element) =>
@@ -236,6 +292,9 @@
       element.name == 'NativeFunctionPointer' &&
       element.library.name == _dartFfiLibraryName;
 
+  bool _isNativeStructPointerExtension(Element element) =>
+      element.name == 'StructPointer' && element.library.name == 'dart.ffi';
+
   /// Returns `true` iff [nativeType] is a `ffi.NativeType` type.
   bool _isNativeTypeInterfaceType(DartType nativeType) {
     if (nativeType is InterfaceType) {
@@ -334,6 +393,7 @@
   }
 
   /// Validates that the given [nativeType] is a valid dart:ffi native type.
+  // TODO(https://dartbug.com/44747): Change to named arguments.
   bool _isValidFfiNativeType(
       DartType nativeType, bool allowVoid, bool allowEmptyStruct) {
     if (nativeType is InterfaceType) {
@@ -569,6 +629,24 @@
     }
   }
 
+  void _validateElementAt(MethodInvocation node) {
+    Expression target = node.realTarget;
+    DartType targetType = target.staticType;
+    if (targetType is InterfaceType &&
+        _isPointer(targetType.element) &&
+        targetType.typeArguments.length == 1) {
+      final DartType T = targetType.typeArguments[0];
+
+      if (!_isValidFfiNativeType(T, true, true)) {
+        final AstNode errorNode = node;
+        _errorReporter.reportErrorForNode(
+            FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING,
+            errorNode,
+            ['elementAt']);
+      }
+    }
+  }
+
   /// Validate that the fields declared by the given [node] meet the
   /// requirements for fields within a struct class.
   void _validateFieldsInStruct(FieldDeclaration node) {
@@ -693,6 +771,44 @@
     }
   }
 
+  void _validateRefIndexed(IndexExpression node) {
+    DartType targetType = node.target.staticType;
+    if (!_isValidFfiNativeType(targetType, false, true)) {
+      final AstNode errorNode = node;
+      _errorReporter.reportErrorForNode(
+          FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING, errorNode, ['[]']);
+    }
+  }
+
+  /// Validate the invocation of the extension method
+  /// `Pointer<T extends Struct>.ref`.
+  void _validateRefPrefixedIdentifier(PrefixedIdentifier node) {
+    DartType targetType = node.prefix.staticType;
+    if (!_isValidFfiNativeType(targetType, false, true)) {
+      final AstNode errorNode = node;
+      _errorReporter.reportErrorForNode(
+          FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING, errorNode, ['ref']);
+    }
+  }
+
+  void _validateRefPropertyAccess(PropertyAccess node) {
+    DartType targetType = node.target.staticType;
+    if (!_isValidFfiNativeType(targetType, false, true)) {
+      final AstNode errorNode = node;
+      _errorReporter.reportErrorForNode(
+          FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING, errorNode, ['ref']);
+    }
+  }
+
+  void _validateSizeOf(MethodInvocation node) {
+    final DartType T = node.typeArgumentTypes[0];
+    if (!_isValidFfiNativeType(T, true, true)) {
+      final AstNode errorNode = node;
+      _errorReporter.reportErrorForNode(
+          FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING, errorNode, ['sizeOf']);
+    }
+  }
+
   /// Validate that the given [typeArgument] has a constant value. Return `true`
   /// if a diagnostic was produced because it isn't constant.
   bool _validateTypeArgument(TypeAnnotation typeArgument, String functionName) {
diff --git a/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart b/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart
index d5ca275..e52db81 100644
--- a/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart
@@ -39,6 +39,7 @@
 class S extends Struct {}
 class C implements S {}
 ''', [
+      error(FfiCode.EMPTY_STRUCT_WARNING, 19, 25),
       error(FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS, 64, 1),
     ]);
   }
@@ -52,6 +53,7 @@
 class S extends Struct {}
 class C with S {}
 ''', [
+      error(FfiCode.EMPTY_STRUCT_WARNING, 19, 25),
       error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 58, 1),
       error(FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_WITH, 58, 1),
     ]);
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index c816637..547bbb2 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -54,6 +54,7 @@
         noLength,
         templateFfiDartTypeMismatch,
         templateFfiEmptyStruct,
+        templateFfiEmptyStructWarning,
         templateFfiExpectedExceptionalReturn,
         templateFfiExpectedNoExceptionalReturn,
         templateFfiExtendsOrImplementsSealedClass,
@@ -61,6 +62,7 @@
         templateFfiFieldCyclic,
         templateFfiFieldInitializer,
         templateFfiFieldNoAnnotation,
+        templateFfiNonConstantTypeArgumentWarning,
         templateFfiNotStatic,
         templateFfiStructGeneric,
         templateFfiTypeInvalid,
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index ce2ddc7..90141d2 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -35,6 +35,8 @@
 import 'package:kernel/type_environment.dart'
     show SubtypeCheckMode, TypeEnvironment;
 
+import 'package:kernel/src/legacy_erasure.dart';
+
 import 'package:kernel/src/types.dart' show Types;
 
 import '../dill/dill_member_builder.dart';
@@ -609,7 +611,13 @@
   Supertype buildSupertype(
       LibraryBuilder library, List<TypeBuilder> arguments) {
     Class cls = isPatch ? origin.cls : this.cls;
-    return new Supertype(cls, buildTypeArguments(library, arguments));
+    List<DartType> typeArguments = buildTypeArguments(library, arguments);
+    if (!library.isNonNullableByDefault) {
+      for (int i = 0; i < typeArguments.length; ++i) {
+        typeArguments[i] = legacyErasure(typeArguments[i]);
+      }
+    }
+    return new Supertype(cls, typeArguments);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
index 8a9751d..3b8fe9b 100644
--- a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
@@ -19,7 +19,9 @@
 import 'package:front_end/src/fasta/builder/procedure_builder.dart';
 
 import 'package:kernel/ast.dart'
-    show DynamicType, Expression, VariableDeclaration;
+    show DartType, DynamicType, Expression, VariableDeclaration;
+
+import 'package:kernel/src/legacy_erasure.dart';
 
 import '../constant_context.dart' show ConstantContext;
 
@@ -119,8 +121,12 @@
       SourceLibraryBuilder library, int functionNestingLevel,
       [bool notInstanceContext]) {
     if (variable == null) {
+      DartType builtType = type?.build(library, null, notInstanceContext);
+      if (!library.isNonNullableByDefault && builtType != null) {
+        builtType = legacyErasure(builtType);
+      }
       variable = new VariableDeclarationImpl(name, functionNestingLevel,
-          type: type?.build(library, null, notInstanceContext),
+          type: builtType,
           isFinal: isFinal,
           isConst: isConst,
           isFieldFormal: isInitializingFormal,
diff --git a/pkg/front_end/lib/src/fasta/builder/never_type_declaration_builder.dart b/pkg/front_end/lib/src/fasta/builder/never_type_declaration_builder.dart
index c4d2e42..61bcbc8 100644
--- a/pkg/front_end/lib/src/fasta/builder/never_type_declaration_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/never_type_declaration_builder.dart
@@ -6,7 +6,7 @@
 
 library fasta.never_type_builder;
 
-import 'package:kernel/ast.dart' show DartType, NullType, Nullability;
+import 'package:kernel/ast.dart' show DartType, Nullability;
 
 import 'builtin_type_declaration_builder.dart';
 import 'library_builder.dart';
@@ -26,17 +26,11 @@
   DartType buildType(LibraryBuilder library,
       NullabilityBuilder nullabilityBuilder, List<TypeBuilder> arguments,
       [bool notInstanceContext]) {
-    if (!library.isNonNullableByDefault) {
-      return const NullType();
-    }
     return type.withDeclaredNullability(nullabilityBuilder.build(library));
   }
 
   DartType buildTypesWithBuiltArguments(LibraryBuilder library,
       Nullability nullability, List<DartType> arguments) {
-    if (!library.isNonNullableByDefault) {
-      return const NullType();
-    }
     return type.withDeclaredNullability(nullability);
   }
 }
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 a145ee7..0d94cfb 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
@@ -916,6 +916,35 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(DartType _type, bool isNonNullableByDefault)>
+    templateFfiNonConstantTypeArgumentWarning = const Template<
+            Message Function(DartType _type, bool isNonNullableByDefault)>(
+        messageTemplate:
+            r"""Support for using non-constant type arguments '#type' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type.""",
+        withArguments: _withArgumentsFfiNonConstantTypeArgumentWarning);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(DartType _type, bool isNonNullableByDefault)>
+    codeFfiNonConstantTypeArgumentWarning =
+    const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
+        "FfiNonConstantTypeArgumentWarning",
+        analyzerCodes: <String>["NON_CONSTANT_TYPE_ARGUMENT_WARNING"],
+        severity: Severity.info);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFfiNonConstantTypeArgumentWarning(
+    DartType _type, bool isNonNullableByDefault) {
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  String type = typeParts.join();
+  return new Message(codeFfiNonConstantTypeArgumentWarning,
+      message:
+          """Support for using non-constant type arguments '${type}' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type.""" +
+              labeler.originMessages,
+      arguments: {'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
         DartType _type,
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index e332dbd..02b7300 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -29,7 +29,9 @@
 import 'package:kernel/clone.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/kernel.dart';
+import 'package:kernel/src/const_canonical_type.dart';
 import 'package:kernel/src/legacy_erasure.dart';
+import 'package:kernel/src/norm.dart';
 import 'package:kernel/src/printer.dart' show AstPrinter, AstTextStrategy;
 import 'package:kernel/type_algebra.dart';
 import 'package:kernel/type_environment.dart';
@@ -200,8 +202,12 @@
 
   @override
   Constant visitMapConstant(MapConstant node) {
-    DartType keyType = rawLegacyErasure(node.keyType);
-    DartType valueType = rawLegacyErasure(node.valueType);
+    DartType keyType = computeConstCanonicalType(
+        node.keyType, _evaluator.coreTypes,
+        isNonNullableByDefault: _evaluator.isNonNullableByDefault);
+    DartType valueType = computeConstCanonicalType(
+        node.valueType, _evaluator.coreTypes,
+        isNonNullableByDefault: _evaluator.isNonNullableByDefault);
     List<ConstantMapEntry> entries;
     for (int index = 0; index < node.entries.length; index++) {
       ConstantMapEntry entry = node.entries[index];
@@ -222,7 +228,9 @@
 
   @override
   Constant visitListConstant(ListConstant node) {
-    DartType typeArgument = rawLegacyErasure(node.typeArgument);
+    DartType typeArgument = computeConstCanonicalType(
+        node.typeArgument, _evaluator.coreTypes,
+        isNonNullableByDefault: _evaluator.isNonNullableByDefault);
     List<Constant> entries;
     for (int index = 0; index < node.entries.length; index++) {
       Constant entry = visitConstant(node.entries[index]);
@@ -240,7 +248,9 @@
 
   @override
   Constant visitSetConstant(SetConstant node) {
-    DartType typeArgument = rawLegacyErasure(node.typeArgument);
+    DartType typeArgument = computeConstCanonicalType(
+        node.typeArgument, _evaluator.coreTypes,
+        isNonNullableByDefault: _evaluator.isNonNullableByDefault);
     List<Constant> entries;
     for (int index = 0; index < node.entries.length; index++) {
       Constant entry = visitConstant(node.entries[index]);
@@ -260,7 +270,9 @@
   Constant visitInstanceConstant(InstanceConstant node) {
     List<DartType> typeArguments;
     for (int index = 0; index < node.typeArguments.length; index++) {
-      DartType typeArgument = rawLegacyErasure(node.typeArguments[index]);
+      DartType typeArgument = computeConstCanonicalType(
+          node.typeArguments[index], _evaluator.coreTypes,
+          isNonNullableByDefault: _evaluator.isNonNullableByDefault);
       if (typeArgument != null) {
         typeArguments ??= node.typeArguments.toList(growable: false);
         typeArguments[index] = typeArgument;
@@ -286,7 +298,9 @@
       PartialInstantiationConstant node) {
     List<DartType> types;
     for (int index = 0; index < node.types.length; index++) {
-      DartType type = rawLegacyErasure(node.types[index]);
+      DartType type = computeConstCanonicalType(
+          node.types[index], _evaluator.coreTypes,
+          isNonNullableByDefault: _evaluator.isNonNullableByDefault);
       if (type != null) {
         types ??= node.types.toList(growable: false);
         types[index] = type;
@@ -303,7 +317,8 @@
 
   @override
   Constant visitTypeLiteralConstant(TypeLiteralConstant node) {
-    DartType type = rawLegacyErasure(node.type);
+    DartType type = computeConstCanonicalType(node.type, _evaluator.coreTypes,
+        isNonNullableByDefault: _evaluator.isNonNullableByDefault);
     if (type != null) {
       return new TypeLiteralConstant(type);
     }
@@ -705,6 +720,14 @@
   }
 
   @override
+  Expression visitTypeLiteral(TypeLiteral node) {
+    if (!containsFreeTypeVariables(node.type)) {
+      return evaluateAndTransformWithContext(node, node);
+    }
+    return super.visitTypeLiteral(node);
+  }
+
+  @override
   Expression visitMapConcatenation(MapConcatenation node) {
     return evaluateAndTransformWithContext(node, node);
   }
@@ -849,9 +872,10 @@
     switch (evaluationMode) {
       case EvaluationMode.strong:
       case EvaluationMode.agnostic:
-        return type;
+        return norm(coreTypes, type);
       case EvaluationMode.weak:
-        return legacyErasure(type);
+        return computeConstCanonicalType(norm(coreTypes, type), coreTypes,
+            isNonNullableByDefault: isNonNullableByDefault);
     }
     throw new UnsupportedError(
         "Unexpected evaluation mode: ${evaluationMode}.");
@@ -861,9 +885,13 @@
     switch (evaluationMode) {
       case EvaluationMode.strong:
       case EvaluationMode.agnostic:
-        return types;
+        return types.map((DartType type) => norm(coreTypes, type)).toList();
       case EvaluationMode.weak:
-        return types.map((DartType type) => legacyErasure(type)).toList();
+        return types
+            .map((DartType type) => computeConstCanonicalType(
+                norm(coreTypes, type), coreTypes,
+                isNonNullableByDefault: isNonNullableByDefault))
+            .toList();
     }
     throw new UnsupportedError(
         "Unexpected evaluation mode: ${evaluationMode}.");
@@ -1147,7 +1175,10 @@
 
   @override
   Constant visitTypeLiteral(TypeLiteral node) {
-    final DartType type = _evaluateDartType(node, node.type);
+    DartType type = _evaluateDartType(node, node.type);
+    if (type != null) {
+      type = convertType(type);
+    }
     if (type == null && _gotError != null) {
       AbortConstant error = _gotError;
       _gotError = null;
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
index 5e3122c..fd6c2f6e 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
@@ -376,7 +376,8 @@
     //
     // Under constraint _ <: X <: Q.
     if (p is TypeParameterType &&
-        isTypeParameterTypeWithoutNullabilityMarker(p, _currentLibrary) &&
+        isTypeParameterTypeWithoutNullabilityMarker(p,
+            isNonNullableByDefault: _currentLibrary.isNonNullableByDefault) &&
         _parametersToConstrain.contains(p.parameter)) {
       _constrainParameterUpper(p.parameter, q);
       return true;
@@ -386,7 +387,8 @@
     //
     // Under constraint P <: X <: _.
     if (q is TypeParameterType &&
-        isTypeParameterTypeWithoutNullabilityMarker(q, _currentLibrary) &&
+        isTypeParameterTypeWithoutNullabilityMarker(q,
+            isNonNullableByDefault: _currentLibrary.isNonNullableByDefault) &&
         _parametersToConstrain.contains(q.parameter)) {
       _constrainParameterLower(q.parameter, p);
       return true;
@@ -405,9 +407,12 @@
     // If P is a legacy type P0* then the match holds under constraint set C:
     //
     // Only if P0 is a subtype match for Q under constraint set C.
-    if (isLegacyTypeConstructorApplication(p, _currentLibrary)) {
+    if (isLegacyTypeConstructorApplication(p,
+        isNonNullableByDefault: _currentLibrary.isNonNullableByDefault)) {
       return _isNullabilityAwareSubtypeMatch(
-          computeTypeWithoutNullabilityMarker(p, _currentLibrary), q,
+          computeTypeWithoutNullabilityMarker(p,
+              isNonNullableByDefault: _currentLibrary.isNonNullableByDefault),
+          q,
           constrainSupertype: constrainSupertype);
     }
 
@@ -417,12 +422,16 @@
     // set C.
     // Or if P is not dynamic or void and P is a subtype match for Q0? under
     // constraint set C.
-    if (isLegacyTypeConstructorApplication(q, _currentLibrary)) {
+    if (isLegacyTypeConstructorApplication(q,
+        isNonNullableByDefault: _currentLibrary.isNonNullableByDefault)) {
       final int baseConstraintCount = _protoConstraints.length;
 
       if ((p is DynamicType || p is VoidType) &&
           _isNullabilityAwareSubtypeMatch(
-              p, computeTypeWithoutNullabilityMarker(q, _currentLibrary),
+              p,
+              computeTypeWithoutNullabilityMarker(q,
+                  isNonNullableByDefault:
+                      _currentLibrary.isNonNullableByDefault),
               constrainSupertype: constrainSupertype)) {
         return true;
       }
@@ -487,10 +496,10 @@
     // Or if P is a subtype match for Q0 under empty constraint set C.
     if (isNullableTypeConstructorApplication(q)) {
       final int baseConstraintCount = _protoConstraints.length;
-      final DartType rawP =
-          computeTypeWithoutNullabilityMarker(p, _currentLibrary);
-      final DartType rawQ =
-          computeTypeWithoutNullabilityMarker(q, _currentLibrary);
+      final DartType rawP = computeTypeWithoutNullabilityMarker(p,
+          isNonNullableByDefault: _currentLibrary.isNonNullableByDefault);
+      final DartType rawQ = computeTypeWithoutNullabilityMarker(q,
+          isNonNullableByDefault: _currentLibrary.isNonNullableByDefault);
 
       if (isNullableTypeConstructorApplication(p) &&
           _isNullabilityAwareSubtypeMatch(rawP, rawQ,
@@ -551,7 +560,10 @@
     if (isNullableTypeConstructorApplication(p)) {
       final int baseConstraintCount = _protoConstraints.length;
       if (_isNullabilityAwareSubtypeMatch(
-              computeTypeWithoutNullabilityMarker(p, _currentLibrary), q,
+              computeTypeWithoutNullabilityMarker(p,
+                  isNonNullableByDefault:
+                      _currentLibrary.isNonNullableByDefault),
+              q,
               constrainSupertype: constrainSupertype) &&
           _isNullabilityAwareSubtypeMatch(const NullType(), q,
               constrainSupertype: constrainSupertype)) {
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 783baee..2e197e9 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4238,6 +4238,13 @@
   template: "Struct '#name' is empty. Empty structs are undefined behavior."
   external: test/ffi_test.dart
 
+FfiEmptyStructWarning:
+  # Used by dart:ffi
+  template: "Struct '#name' is empty. Support for empty structs is deprecated and will be removed in the next stable version of Dart. Use Opaque instead."
+  analyzerCode: EMPTY_STRUCT_WARNING
+  severity: INFO
+  external: test/ffi_test.dart
+
 FfiTypeInvalid:
   # Used by dart:ffi
   template: "Expected type '#type' to be a valid and instantiated subtype of 'NativeType'."
@@ -4260,6 +4267,13 @@
     #names
   external: test/ffi_test.dart
 
+FfiNonConstantTypeArgumentWarning:
+  # Used by dart:ffi
+  template: "Support for using non-constant type arguments '#type' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type."
+  analyzerCode: NON_CONSTANT_TYPE_ARGUMENT_WARNING
+  severity: INFO
+  external: test/ffi_test.dart
+
 FfiNotStatic:
   # Used by dart:ffi
   template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code."
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 691e56f..19c21c2 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -1027,6 +1027,7 @@
       ..allowedExperimentalFlagsForTesting = allowedExperimentalFlags
       ..experimentEnabledVersionForTesting = experimentEnabledVersion
       ..experimentReleasedVersionForTesting = experimentReleasedVersion
+      ..verifySkipPlatform = true
       ..target = createTarget(folderOptions, context);
     if (folderOptions.overwriteCurrentSdkVersion != null) {
       compilerOptions.currentSdkVersion =
@@ -1366,30 +1367,32 @@
 
   Future<Result<ComponentResult>> run(
       ComponentResult result, FastaContext context) async {
-    Component component = result.component;
-    KernelTarget sourceTarget = context.componentToTarget[component];
-    context.componentToTarget.remove(component);
-    Target backendTarget = sourceTarget.backendTarget;
-    if (backendTarget is TestVmTarget) {
-      backendTarget.enabled = true;
-    }
-    try {
-      if (sourceTarget.loader.coreTypes != null) {
-        sourceTarget.runBuildTransformations();
-      }
-    } finally {
+    return await CompilerContext.runWithOptions(result.options, (_) async {
+      Component component = result.component;
+      KernelTarget sourceTarget = context.componentToTarget[component];
+      context.componentToTarget.remove(component);
+      Target backendTarget = sourceTarget.backendTarget;
       if (backendTarget is TestVmTarget) {
-        backendTarget.enabled = false;
+        backendTarget.enabled = true;
       }
-    }
-    List<String> errors = VerifyTransformed.verify(component);
-    if (errors.isNotEmpty) {
-      return new Result<ComponentResult>(
-          result,
-          context.expectationSet["TransformVerificationError"],
-          errors.join('\n'));
-    }
-    return pass(result);
+      try {
+        if (sourceTarget.loader.coreTypes != null) {
+          sourceTarget.runBuildTransformations();
+        }
+      } finally {
+        if (backendTarget is TestVmTarget) {
+          backendTarget.enabled = false;
+        }
+      }
+      List<String> errors = VerifyTransformed.verify(component);
+      if (errors.isNotEmpty) {
+        return new Result<ComponentResult>(
+            result,
+            context.expectationSet["TransformVerificationError"],
+            errors.join('\n'));
+      }
+      return pass(result);
+    });
   }
 }
 
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 9ff711a..9b60eea 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -829,6 +829,7 @@
 detected
 detecting
 detection
+detector
 detects
 determination
 determine
@@ -1285,6 +1286,7 @@
 gathering
 general
 generalized
+generalizes
 generally
 generate
 generated
@@ -2435,6 +2437,7 @@
 references
 referencing
 referred
+referring
 refers
 refine
 refinement
diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt
index d754653..f8c8578 100644
--- a/pkg/front_end/test/spell_checking_list_messages.txt
+++ b/pkg/front_end/test/spell_checking_list_messages.txt
@@ -11,6 +11,7 @@
 
 JS
 adjusting
+api
 argument(s)
 assigning
 b
@@ -29,6 +30,7 @@
 e.g
 enum's
 f
+ffi
 flutter_runner
 futureor
 h
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index f2defc9..55be1a1 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -98,6 +98,7 @@
 cc
 ccc
 cell
+cf
 charset
 checkme
 checkout
@@ -511,7 +512,10 @@
 okay
 ol
 onull
+oo
+oocf
 ooo
+oovf
 opacity
 operate
 ops
@@ -756,6 +760,7 @@
 vars
 verbatim
 versioned
+vf
 vp
 vt
 vte
diff --git a/pkg/front_end/testcases/agnostic/as.dart.weak.expect b/pkg/front_end/testcases/agnostic/as.dart.weak.expect
index f28c31a..40e7073 100644
--- a/pkg/front_end/testcases/agnostic/as.dart.weak.expect
+++ b/pkg/front_end/testcases/agnostic/as.dart.weak.expect
@@ -8,5 +8,5 @@
 
 constants  {
   #C1 = <Null>[]
-  #C2 = <core::int*>[]
+  #C2 = <core::int?>[]
 }
diff --git a/pkg/front_end/testcases/agnostic/as.dart.weak.transformed.expect b/pkg/front_end/testcases/agnostic/as.dart.weak.transformed.expect
index f28c31a..40e7073 100644
--- a/pkg/front_end/testcases/agnostic/as.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/agnostic/as.dart.weak.transformed.expect
@@ -8,5 +8,5 @@
 
 constants  {
   #C1 = <Null>[]
-  #C2 = <core::int*>[]
+  #C2 = <core::int?>[]
 }
diff --git a/pkg/front_end/testcases/agnostic/identical.dart.outline.expect b/pkg/front_end/testcases/agnostic/identical.dart.outline.expect
index a3ec3dc..6f87884 100644
--- a/pkg/front_end/testcases/agnostic/identical.dart.outline.expect
+++ b/pkg/front_end/testcases/agnostic/identical.dart.outline.expect
@@ -12,6 +12,5 @@
 Extra constant evaluation status:
 Evaluated: ListLiteral @ org-dartlang-testcase:///identical.dart:5:16 -> ListConstant(const <int>[])
 Evaluated: ListLiteral @ org-dartlang-testcase:///identical.dart:6:17 -> ListConstant(const <int?>[])
-Evaluated: StaticGet @ org-dartlang-testcase:///identical.dart:7:21 -> ListConstant(const <int>[])
-Evaluated: StaticGet @ org-dartlang-testcase:///identical.dart:7:24 -> ListConstant(const <int?>[])
-Extra constant evaluation: evaluated: 5, effectively constant: 4
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical.dart:7:11 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 3, effectively constant: 3
diff --git a/pkg/front_end/testcases/agnostic/identical.dart.strong.expect b/pkg/front_end/testcases/agnostic/identical.dart.strong.expect
index fd8a51e..0e4519e 100644
--- a/pkg/front_end/testcases/agnostic/identical.dart.strong.expect
+++ b/pkg/front_end/testcases/agnostic/identical.dart.strong.expect
@@ -1,26 +1,14 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/agnostic/identical.dart:7:11: Error: Constant evaluation error:
-// const c = identical(a, b);
-//           ^
-// pkg/front_end/testcases/agnostic/identical.dart:7:11: Context: Constant value is not strong/weak mode agnostic.
-// const c = identical(a, b);
-//           ^
-// pkg/front_end/testcases/agnostic/identical.dart:7:7: Context: While analyzing:
-// const c = identical(a, b);
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
 static const field core::List<core::int?> b = #C2;
-static const field core::bool c = invalid-expression "Constant value is not strong/weak mode agnostic.";
+static const field core::bool c = #C3;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int>[]
   #C2 = <core::int?>[]
+  #C3 = false
 }
diff --git a/pkg/front_end/testcases/agnostic/identical.dart.strong.transformed.expect b/pkg/front_end/testcases/agnostic/identical.dart.strong.transformed.expect
index fd8a51e..0e4519e 100644
--- a/pkg/front_end/testcases/agnostic/identical.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/agnostic/identical.dart.strong.transformed.expect
@@ -1,26 +1,14 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/agnostic/identical.dart:7:11: Error: Constant evaluation error:
-// const c = identical(a, b);
-//           ^
-// pkg/front_end/testcases/agnostic/identical.dart:7:11: Context: Constant value is not strong/weak mode agnostic.
-// const c = identical(a, b);
-//           ^
-// pkg/front_end/testcases/agnostic/identical.dart:7:7: Context: While analyzing:
-// const c = identical(a, b);
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
 static const field core::List<core::int?> b = #C2;
-static const field core::bool c = invalid-expression "Constant value is not strong/weak mode agnostic.";
+static const field core::bool c = #C3;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int>[]
   #C2 = <core::int?>[]
+  #C3 = false
 }
diff --git a/pkg/front_end/testcases/agnostic/identical.dart.weak.expect b/pkg/front_end/testcases/agnostic/identical.dart.weak.expect
index 4a31c8f..f5a7aaa 100644
--- a/pkg/front_end/testcases/agnostic/identical.dart.weak.expect
+++ b/pkg/front_end/testcases/agnostic/identical.dart.weak.expect
@@ -3,11 +3,12 @@
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
-static const field core::List<core::int?> b = #C1;
-static const field core::bool c = #C2;
+static const field core::List<core::int?> b = #C2;
+static const field core::bool c = #C3;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int*>[]
-  #C2 = true
+  #C2 = <core::int?>[]
+  #C3 = false
 }
diff --git a/pkg/front_end/testcases/agnostic/identical.dart.weak.transformed.expect b/pkg/front_end/testcases/agnostic/identical.dart.weak.transformed.expect
index 4a31c8f..f5a7aaa 100644
--- a/pkg/front_end/testcases/agnostic/identical.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/agnostic/identical.dart.weak.transformed.expect
@@ -3,11 +3,12 @@
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
-static const field core::List<core::int?> b = #C1;
-static const field core::bool c = #C2;
+static const field core::List<core::int?> b = #C2;
+static const field core::bool c = #C3;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int*>[]
-  #C2 = true
+  #C2 = <core::int?>[]
+  #C3 = false
 }
diff --git a/pkg/front_end/testcases/agnostic/map.dart.outline.expect b/pkg/front_end/testcases/agnostic/map.dart.outline.expect
index e1ceefa..5661432 100644
--- a/pkg/front_end/testcases/agnostic/map.dart.outline.expect
+++ b/pkg/front_end/testcases/agnostic/map.dart.outline.expect
@@ -12,6 +12,5 @@
 Extra constant evaluation status:
 Evaluated: ListLiteral @ org-dartlang-testcase:///map.dart:5:16 -> ListConstant(const <int>[])
 Evaluated: ListLiteral @ org-dartlang-testcase:///map.dart:6:17 -> ListConstant(const <int?>[])
-Evaluated: StaticGet @ org-dartlang-testcase:///map.dart:7:12 -> ListConstant(const <int>[])
-Evaluated: StaticGet @ org-dartlang-testcase:///map.dart:7:18 -> ListConstant(const <int?>[])
-Extra constant evaluation: evaluated: 5, effectively constant: 4
+Evaluated: MapLiteral @ org-dartlang-testcase:///map.dart:7:11 -> InstanceConstant(const _ImmutableMap<List<int?>, int>{_ImmutableMap._kvPairs: const <dynamic>[const <int>[], 0, const <int?>[], 1]})
+Extra constant evaluation: evaluated: 3, effectively constant: 3
diff --git a/pkg/front_end/testcases/agnostic/map.dart.strong.expect b/pkg/front_end/testcases/agnostic/map.dart.strong.expect
index 021aca0..4802fa3 100644
--- a/pkg/front_end/testcases/agnostic/map.dart.strong.expect
+++ b/pkg/front_end/testcases/agnostic/map.dart.strong.expect
@@ -1,26 +1,17 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/agnostic/map.dart:7:11: Error: Constant evaluation error:
-// const c = {a: 0, b: 1};
-//           ^
-// pkg/front_end/testcases/agnostic/map.dart:7:18: Context: Constant value is not strong/weak mode agnostic.
-// const c = {a: 0, b: 1};
-//                  ^
-// pkg/front_end/testcases/agnostic/map.dart:7:7: Context: While analyzing:
-// const c = {a: 0, b: 1};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
 static const field core::List<core::int?> b = #C2;
-static const field core::Map<core::List<core::int?>, core::int> c = invalid-expression "Constant value is not strong/weak mode agnostic.";
+static const field core::Map<core::List<core::int?>, core::int> c = #C6;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int>[]
   #C2 = <core::int?>[]
+  #C3 = 0
+  #C4 = 1
+  #C5 = <dynamic>[#C1, #C3, #C2, #C4]
+  #C6 = core::_ImmutableMap<core::List<core::int?>, core::int> {_kvPairs:#C5}
 }
diff --git a/pkg/front_end/testcases/agnostic/map.dart.strong.transformed.expect b/pkg/front_end/testcases/agnostic/map.dart.strong.transformed.expect
index 021aca0..4802fa3 100644
--- a/pkg/front_end/testcases/agnostic/map.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/agnostic/map.dart.strong.transformed.expect
@@ -1,26 +1,17 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/agnostic/map.dart:7:11: Error: Constant evaluation error:
-// const c = {a: 0, b: 1};
-//           ^
-// pkg/front_end/testcases/agnostic/map.dart:7:18: Context: Constant value is not strong/weak mode agnostic.
-// const c = {a: 0, b: 1};
-//                  ^
-// pkg/front_end/testcases/agnostic/map.dart:7:7: Context: While analyzing:
-// const c = {a: 0, b: 1};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
 static const field core::List<core::int?> b = #C2;
-static const field core::Map<core::List<core::int?>, core::int> c = invalid-expression "Constant value is not strong/weak mode agnostic.";
+static const field core::Map<core::List<core::int?>, core::int> c = #C6;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int>[]
   #C2 = <core::int?>[]
+  #C3 = 0
+  #C4 = 1
+  #C5 = <dynamic>[#C1, #C3, #C2, #C4]
+  #C6 = core::_ImmutableMap<core::List<core::int?>, core::int> {_kvPairs:#C5}
 }
diff --git a/pkg/front_end/testcases/agnostic/map.dart.weak.expect b/pkg/front_end/testcases/agnostic/map.dart.weak.expect
index 1d3e649..2104776 100644
--- a/pkg/front_end/testcases/agnostic/map.dart.weak.expect
+++ b/pkg/front_end/testcases/agnostic/map.dart.weak.expect
@@ -1,25 +1,17 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/agnostic/map.dart:7:11: Error: Constant evaluation error:
-// const c = {a: 0, b: 1};
-//           ^
-// pkg/front_end/testcases/agnostic/map.dart:7:18: Context: The key '<int>[]' conflicts with another existing key in the map.
-// const c = {a: 0, b: 1};
-//                  ^
-// pkg/front_end/testcases/agnostic/map.dart:7:7: Context: While analyzing:
-// const c = {a: 0, b: 1};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
-static const field core::List<core::int?> b = #C1;
-static const field core::Map<core::List<core::int?>, core::int> c = invalid-expression "The key '<int>[]' conflicts with another existing key in the map.";
+static const field core::List<core::int?> b = #C2;
+static const field core::Map<core::List<core::int?>, core::int> c = #C6;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int*>[]
+  #C2 = <core::int?>[]
+  #C3 = 0
+  #C4 = 1
+  #C5 = <dynamic>[#C1, #C3, #C2, #C4]
+  #C6 = core::_ImmutableMap<core::List<core::int?>*, core::int*> {_kvPairs:#C5}
 }
diff --git a/pkg/front_end/testcases/agnostic/map.dart.weak.transformed.expect b/pkg/front_end/testcases/agnostic/map.dart.weak.transformed.expect
index 1d3e649..2104776 100644
--- a/pkg/front_end/testcases/agnostic/map.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/agnostic/map.dart.weak.transformed.expect
@@ -1,25 +1,17 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/agnostic/map.dart:7:11: Error: Constant evaluation error:
-// const c = {a: 0, b: 1};
-//           ^
-// pkg/front_end/testcases/agnostic/map.dart:7:18: Context: The key '<int>[]' conflicts with another existing key in the map.
-// const c = {a: 0, b: 1};
-//                  ^
-// pkg/front_end/testcases/agnostic/map.dart:7:7: Context: While analyzing:
-// const c = {a: 0, b: 1};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
-static const field core::List<core::int?> b = #C1;
-static const field core::Map<core::List<core::int?>, core::int> c = invalid-expression "The key '<int>[]' conflicts with another existing key in the map.";
+static const field core::List<core::int?> b = #C2;
+static const field core::Map<core::List<core::int?>, core::int> c = #C6;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int*>[]
+  #C2 = <core::int?>[]
+  #C3 = 0
+  #C4 = 1
+  #C5 = <dynamic>[#C1, #C3, #C2, #C4]
+  #C6 = core::_ImmutableMap<core::List<core::int?>*, core::int*> {_kvPairs:#C5}
 }
diff --git a/pkg/front_end/testcases/agnostic/set.dart.outline.expect b/pkg/front_end/testcases/agnostic/set.dart.outline.expect
index 53dca31..a0da86e 100644
--- a/pkg/front_end/testcases/agnostic/set.dart.outline.expect
+++ b/pkg/front_end/testcases/agnostic/set.dart.outline.expect
@@ -12,6 +12,5 @@
 Extra constant evaluation status:
 Evaluated: ListLiteral @ org-dartlang-testcase:///set.dart:5:16 -> ListConstant(const <int>[])
 Evaluated: ListLiteral @ org-dartlang-testcase:///set.dart:6:17 -> ListConstant(const <int?>[])
-Evaluated: StaticGet @ org-dartlang-testcase:///set.dart:7:12 -> ListConstant(const <int>[])
-Evaluated: StaticGet @ org-dartlang-testcase:///set.dart:7:15 -> ListConstant(const <int?>[])
-Extra constant evaluation: evaluated: 5, effectively constant: 4
+Evaluated: SetLiteral @ org-dartlang-testcase:///set.dart:7:11 -> InstanceConstant(const _UnmodifiableSet<List<int?>>{_UnmodifiableSet._map: const _ImmutableMap<List<int?>, Null>{_ImmutableMap._kvPairs: const <dynamic>[const <int>[], null, const <int?>[], null]}})
+Extra constant evaluation: evaluated: 3, effectively constant: 3
diff --git a/pkg/front_end/testcases/agnostic/set.dart.strong.expect b/pkg/front_end/testcases/agnostic/set.dart.strong.expect
index ad0fc3d..9da7c28 100644
--- a/pkg/front_end/testcases/agnostic/set.dart.strong.expect
+++ b/pkg/front_end/testcases/agnostic/set.dart.strong.expect
@@ -1,26 +1,17 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/agnostic/set.dart:7:11: Error: Constant evaluation error:
-// const c = {a, b};
-//           ^
-// pkg/front_end/testcases/agnostic/set.dart:7:15: Context: Constant value is not strong/weak mode agnostic.
-// const c = {a, b};
-//               ^
-// pkg/front_end/testcases/agnostic/set.dart:7:7: Context: While analyzing:
-// const c = {a, b};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
 static const field core::List<core::int?> b = #C2;
-static const field core::Set<core::List<core::int?>> c = invalid-expression "Constant value is not strong/weak mode agnostic.";
+static const field core::Set<core::List<core::int?>> c = #C6;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int>[]
   #C2 = <core::int?>[]
+  #C3 = null
+  #C4 = <dynamic>[#C1, #C3, #C2, #C3]
+  #C5 = core::_ImmutableMap<core::List<core::int?>, Null> {_kvPairs:#C4}
+  #C6 = col::_UnmodifiableSet<core::List<core::int?>> {_map:#C5}
 }
diff --git a/pkg/front_end/testcases/agnostic/set.dart.strong.transformed.expect b/pkg/front_end/testcases/agnostic/set.dart.strong.transformed.expect
index ad0fc3d..9da7c28 100644
--- a/pkg/front_end/testcases/agnostic/set.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/agnostic/set.dart.strong.transformed.expect
@@ -1,26 +1,17 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/agnostic/set.dart:7:11: Error: Constant evaluation error:
-// const c = {a, b};
-//           ^
-// pkg/front_end/testcases/agnostic/set.dart:7:15: Context: Constant value is not strong/weak mode agnostic.
-// const c = {a, b};
-//               ^
-// pkg/front_end/testcases/agnostic/set.dart:7:7: Context: While analyzing:
-// const c = {a, b};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
 static const field core::List<core::int?> b = #C2;
-static const field core::Set<core::List<core::int?>> c = invalid-expression "Constant value is not strong/weak mode agnostic.";
+static const field core::Set<core::List<core::int?>> c = #C6;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int>[]
   #C2 = <core::int?>[]
+  #C3 = null
+  #C4 = <dynamic>[#C1, #C3, #C2, #C3]
+  #C5 = core::_ImmutableMap<core::List<core::int?>, Null> {_kvPairs:#C4}
+  #C6 = col::_UnmodifiableSet<core::List<core::int?>> {_map:#C5}
 }
diff --git a/pkg/front_end/testcases/agnostic/set.dart.weak.expect b/pkg/front_end/testcases/agnostic/set.dart.weak.expect
index f33d0a9..8c54370 100644
--- a/pkg/front_end/testcases/agnostic/set.dart.weak.expect
+++ b/pkg/front_end/testcases/agnostic/set.dart.weak.expect
@@ -1,25 +1,17 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/agnostic/set.dart:7:11: Error: Constant evaluation error:
-// const c = {a, b};
-//           ^
-// pkg/front_end/testcases/agnostic/set.dart:7:15: Context: The element '<int>[]' conflicts with another existing element in the set.
-// const c = {a, b};
-//               ^
-// pkg/front_end/testcases/agnostic/set.dart:7:7: Context: While analyzing:
-// const c = {a, b};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
-static const field core::List<core::int?> b = #C1;
-static const field core::Set<core::List<core::int?>> c = invalid-expression "The element '<int>[]' conflicts with another existing element in the set.";
+static const field core::List<core::int?> b = #C2;
+static const field core::Set<core::List<core::int?>> c = #C6;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int*>[]
+  #C2 = <core::int?>[]
+  #C3 = null
+  #C4 = <dynamic>[#C1, #C3, #C2, #C3]
+  #C5 = core::_ImmutableMap<core::List<core::int?>*, Null> {_kvPairs:#C4}
+  #C6 = col::_UnmodifiableSet<core::List<core::int?>*> {_map:#C5}
 }
diff --git a/pkg/front_end/testcases/agnostic/set.dart.weak.transformed.expect b/pkg/front_end/testcases/agnostic/set.dart.weak.transformed.expect
index f33d0a9..8c54370 100644
--- a/pkg/front_end/testcases/agnostic/set.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/agnostic/set.dart.weak.transformed.expect
@@ -1,25 +1,17 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/agnostic/set.dart:7:11: Error: Constant evaluation error:
-// const c = {a, b};
-//           ^
-// pkg/front_end/testcases/agnostic/set.dart:7:15: Context: The element '<int>[]' conflicts with another existing element in the set.
-// const c = {a, b};
-//               ^
-// pkg/front_end/testcases/agnostic/set.dart:7:7: Context: While analyzing:
-// const c = {a, b};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 static const field core::List<core::int> a = #C1;
-static const field core::List<core::int?> b = #C1;
-static const field core::Set<core::List<core::int?>> c = invalid-expression "The element '<int>[]' conflicts with another existing element in the set.";
+static const field core::List<core::int?> b = #C2;
+static const field core::Set<core::List<core::int?>> c = #C6;
 static method main() → dynamic {}
 
 constants  {
   #C1 = <core::int*>[]
+  #C2 = <core::int?>[]
+  #C3 = null
+  #C4 = <dynamic>[#C1, #C3, #C2, #C3]
+  #C5 = core::_ImmutableMap<core::List<core::int?>*, Null> {_kvPairs:#C4}
+  #C6 = col::_UnmodifiableSet<core::List<core::int?>*> {_map:#C5}
 }
diff --git a/pkg/front_end/testcases/extensions/type_variable_bound.dart.strong.expect b/pkg/front_end/testcases/extensions/type_variable_bound.dart.strong.expect
index 3dfb6be..a20912a 100644
--- a/pkg/front_end/testcases/extensions/type_variable_bound.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/type_variable_bound.dart.strong.expect
@@ -45,7 +45,7 @@
   return new self::Class::•();
 }
 static method test2<T extends self::Class* = self::Class*>(self::test2::T* t2) → dynamic {
-  if(self::test2::T*.{core::Type::==}(self::SubClass*)) {
+  if(self::test2::T*.{core::Type::==}(#C1)) {
     self::SubClass* subClass = self::BoundExtension|method2<self::Class*>(t2) as{TypeError} self::SubClass*;
   }
 }
@@ -55,3 +55,7 @@
   }
 }
 static method main() → dynamic {}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::SubClass*)
+}
diff --git a/pkg/front_end/testcases/extensions/type_variable_bound.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/type_variable_bound.dart.strong.transformed.expect
index 79b6d8f..a20912a 100644
--- a/pkg/front_end/testcases/extensions/type_variable_bound.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/type_variable_bound.dart.strong.transformed.expect
@@ -45,7 +45,7 @@
   return new self::Class::•();
 }
 static method test2<T extends self::Class* = self::Class*>(self::test2::T* t2) → dynamic {
-  if(self::test2::T*.{core::Type::==}(self::SubClass*)) {
+  if(self::test2::T*.{core::Type::==}(#C1)) {
     self::SubClass* subClass = self::BoundExtension|method2<self::Class*>(t2) as{TypeError} self::SubClass*;
   }
 }
@@ -56,7 +56,6 @@
 }
 static method main() → dynamic {}
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///type_variable_bound.dart:27:12 -> TypeLiteralConstant(SubClass*)
-Extra constant evaluation: evaluated: 23, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(self::SubClass*)
+}
diff --git a/pkg/front_end/testcases/general/bug33099.dart.strong.expect b/pkg/front_end/testcases/general/bug33099.dart.strong.expect
index 2f8e660..7fb694a 100644
--- a/pkg/front_end/testcases/general/bug33099.dart.strong.expect
+++ b/pkg/front_end/testcases/general/bug33099.dart.strong.expect
@@ -61,9 +61,9 @@
 }
 static const field self::_FailingTest* failingTest = #C1;
 static method main() → dynamic {
-  mir::ClassMirror* classMirror = mir::reflectClass(self::MyTest2*);
+  mir::ClassMirror* classMirror = mir::reflectClass(#C2);
   classMirror.{mir::ClassMirror::instanceMembers}.{core::Map::forEach}((core::Symbol* symbol, mir::MethodMirror* memberMirror) → Null {
-    if(memberMirror.{mir::DeclarationMirror::simpleName}.{core::Symbol::==}(#C2)) {
+    if(memberMirror.{mir::DeclarationMirror::simpleName}.{core::Symbol::==}(#C3)) {
       core::print(memberMirror);
       core::print(self::_hasFailingTestAnnotation(memberMirror));
     }
@@ -82,7 +82,8 @@
 
 constants  {
   #C1 = self::_FailingTest {}
-  #C2 = #foo
+  #C2 = TypeLiteralConstant(self::MyTest2*)
+  #C3 = #foo
 }
 
 
diff --git a/pkg/front_end/testcases/general/bug33099.dart.strong.transformed.expect b/pkg/front_end/testcases/general/bug33099.dart.strong.transformed.expect
index 6f4fe0e..188bd50 100644
--- a/pkg/front_end/testcases/general/bug33099.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/bug33099.dart.strong.transformed.expect
@@ -61,9 +61,9 @@
 }
 static const field self::_FailingTest* failingTest = #C1;
 static method main() → dynamic {
-  mir::ClassMirror* classMirror = mir::reflectClass(self::MyTest2*);
+  mir::ClassMirror* classMirror = mir::reflectClass(#C2);
   classMirror.{mir::ClassMirror::instanceMembers}.{core::Map::forEach}((core::Symbol* symbol, mir::MethodMirror* memberMirror) → Null {
-    if(memberMirror.{mir::DeclarationMirror::simpleName}.{core::Symbol::==}(#C2)) {
+    if(memberMirror.{mir::DeclarationMirror::simpleName}.{core::Symbol::==}(#C3)) {
       core::print(memberMirror);
       core::print(self::_hasFailingTestAnnotation(memberMirror));
     }
@@ -82,13 +82,10 @@
 
 constants  {
   #C1 = self::_FailingTest {}
-  #C2 = #foo
+  #C2 = TypeLiteralConstant(self::MyTest2*)
+  #C3 = #foo
 }
 
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///bug33099.dart:21:42 -> TypeLiteralConstant(MyTest2*)
-Extra constant evaluation: evaluated: 33, effectively constant: 1
-
 
 Constructor coverage from constants:
 org-dartlang-testcase:///bug33099.dart:
diff --git a/pkg/front_end/testcases/general/check_deferred_read_type.dart.strong.expect b/pkg/front_end/testcases/general/check_deferred_read_type.dart.strong.expect
index b3ae2c0..efb9d56 100644
--- a/pkg/front_end/testcases/general/check_deferred_read_type.dart.strong.expect
+++ b/pkg/front_end/testcases/general/check_deferred_read_type.dart.strong.expect
@@ -1,22 +1,21 @@
 library;
 import self as self;
 import "dart:core" as core;
-import "deferred_lib.dart" as def;
 
 import "org-dartlang-testcase:///deferred_lib.dart" deferred as lib;
 
 static method main() → dynamic {}
 static method test() → dynamic {
-  core::print(let final dynamic #t1 = CheckLibraryIsLoaded(lib) in def::C*);
+  core::print(let final dynamic #t1 = CheckLibraryIsLoaded(lib) in #C1);
 }
 
 library;
-import self as def;
+import self as self2;
 import "dart:core" as core;
 
 class C extends core::Object {
   static field core::int* y = 1;
-  synthetic constructor •() → def::C*
+  synthetic constructor •() → self2::C*
     : super core::Object::•()
     ;
   static method m() → core::int*
@@ -35,3 +34,7 @@
 static field core::int* x = 0;
 static method m(dynamic x) → dynamic
   return null;
+
+constants  {
+  #C1 = TypeLiteralConstant(self2::C*)
+}
diff --git a/pkg/front_end/testcases/general/check_deferred_read_type.dart.strong.transformed.expect b/pkg/front_end/testcases/general/check_deferred_read_type.dart.strong.transformed.expect
index fdd58da..2813c9c5 100644
--- a/pkg/front_end/testcases/general/check_deferred_read_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/check_deferred_read_type.dart.strong.transformed.expect
@@ -1,22 +1,21 @@
 library;
 import self as self;
 import "dart:core" as core;
-import "deferred_lib.dart" as def;
 
 import "org-dartlang-testcase:///deferred_lib.dart" deferred as lib;
 
 static method main() → dynamic {}
 static method test() → dynamic {
-  core::print(let final core::Object* #t1 = CheckLibraryIsLoaded(lib) in def::C*);
+  core::print(let final core::Object* #t1 = CheckLibraryIsLoaded(lib) in #C1);
 }
 
 library;
-import self as def;
+import self as self2;
 import "dart:core" as core;
 
 class C extends core::Object {
   static field core::int* y = 1;
-  synthetic constructor •() → def::C*
+  synthetic constructor •() → self2::C*
     : super core::Object::•()
     ;
   static method m() → core::int*
@@ -36,7 +35,6 @@
 static method m(dynamic x) → dynamic
   return null;
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///check_deferred_read_type.dart:9:13 -> TypeLiteralConstant(C*)
-Extra constant evaluation: evaluated: 4, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(self2::C*)
+}
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.outline.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.outline.expect
index 8dfa191..76fe0d1 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.outline.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.outline.expect
@@ -36,11 +36,9 @@
 Evaluated: SetLiteral @ org-dartlang-testcase:///const_collections.dart:21:44 -> SetConstant(const <bool>{false})
 Evaluated: ListLiteral @ org-dartlang-testcase:///const_collections.dart:23:16 -> ListConstant(const <int>[])
 Evaluated: ListLiteral @ org-dartlang-testcase:///const_collections.dart:24:17 -> ListConstant(const <int?>[])
-Evaluated: StaticGet @ org-dartlang-testcase:///const_collections.dart:25:27 -> ListConstant(const <int>[])
-Evaluated: StaticGet @ org-dartlang-testcase:///const_collections.dart:25:30 -> ListConstant(const <int?>[])
+Evaluated: SetLiteral @ org-dartlang-testcase:///const_collections.dart:25:26 -> SetConstant(const <List<int?>>{const <int>[], const <int?>[]})
 Evaluated with empty environment: MapLiteral @ org-dartlang-testcase:///const_collections.dart:27:38 -> MapConstant(const <bool, bool>{false: false})
 Evaluated with empty environment: FactoryConstructorInvocationJudgment @ org-dartlang-testcase:///const_collections.dart:28:8 -> BoolConstant(false)
 Evaluated with empty environment: FactoryConstructorInvocationJudgment @ org-dartlang-testcase:///const_collections.dart:28:37 -> BoolConstant(false)
-Evaluated: StaticGet @ org-dartlang-testcase:///const_collections.dart:31:27 -> ListConstant(const <int>[])
-Evaluated: StaticGet @ org-dartlang-testcase:///const_collections.dart:31:33 -> ListConstant(const <int?>[])
-Extra constant evaluation: evaluated: 25, effectively constant: 20
+Evaluated: MapLiteral @ org-dartlang-testcase:///const_collections.dart:31:26 -> MapConstant(const <List<int?>, int>{const <int>[]: 0, const <int?>[]: 1})
+Extra constant evaluation: evaluated: 21, effectively constant: 18
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.strong.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.strong.expect
index d0164af..0fd3e2b 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.strong.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.strong.expect
@@ -6,26 +6,6 @@
 // const Map<bool> MapWithUnevaluated = {
 //       ^
 //
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:25:26: Error: Constant evaluation error:
-// const setNotAgnosticOK = {a, b};
-//                          ^
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:25:30: Context: Constant value is not strong/weak mode agnostic.
-// const setNotAgnosticOK = {a, b};
-//                              ^
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:25:7: Context: While analyzing:
-// const setNotAgnosticOK = {a, b};
-//       ^
-//
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:31:26: Error: Constant evaluation error:
-// const mapNotAgnosticOK = {a: 0, b: 1};
-//                          ^
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:31:33: Context: Constant value is not strong/weak mode agnostic.
-// const mapNotAgnosticOK = {a: 0, b: 1};
-//                                 ^
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:31:7: Context: While analyzing:
-// const mapNotAgnosticOK = {a: 0, b: 1};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
@@ -35,16 +15,16 @@
 static const field core::Set<core::bool> setWithUnevaluatedSpread = #C12;
 static const field core::List<core::int> a = #C13;
 static const field core::List<core::int?> b = #C14;
-static const field core::Set<core::List<core::int?>> setNotAgnosticOK = invalid-expression "Constant value is not strong/weak mode agnostic.";
-static const field invalid-type MapWithUnevaluated = #C15;
-static const field core::Map<core::List<core::int?>, core::int> mapNotAgnosticOK = invalid-expression "Constant value is not strong/weak mode agnostic.";
+static const field core::Set<core::List<core::int?>> setNotAgnosticOK = #C15;
+static const field invalid-type MapWithUnevaluated = #C16;
+static const field core::Map<core::List<core::int?>, core::int> mapNotAgnosticOK = #C19;
 static method main() → dynamic {
   core::print(#C5);
   core::print(#C8);
   core::print(#C10);
   core::print(#C12);
   core::print(<core::String>{"hello"});
-  core::print(#C17);
+  core::print(#C21);
 }
 
 constants  {
@@ -62,7 +42,11 @@
   #C12 = eval #C9 + const <dynamic>{const core::bool::fromEnvironment(#C1)} + const <dynamic>{const core::bool::fromEnvironment(#C2)} + #C9 + #C11
   #C13 = <core::int>[]
   #C14 = <core::int?>[]
-  #C15 = eval const <dynamic, dynamic>{const core::bool::fromEnvironment(#C1): const core::bool::fromEnvironment(#C2)}
-  #C16 = "hello"
-  #C17 = <core::String>{#C16}
+  #C15 = <core::List<core::int?>>{#C13, #C14}
+  #C16 = eval const <dynamic, dynamic>{const core::bool::fromEnvironment(#C1): const core::bool::fromEnvironment(#C2)}
+  #C17 = 0
+  #C18 = 1
+  #C19 = <core::List<core::int?>, core::int>{#C13:#C17, #C14:#C18)
+  #C20 = "hello"
+  #C21 = <core::String>{#C20}
 }
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.strong.transformed.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.strong.transformed.expect
index 734ed41..d9dd342 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart.strong.transformed.expect
@@ -6,26 +6,6 @@
 // const Map<bool> MapWithUnevaluated = {
 //       ^
 //
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:25:26: Error: Constant evaluation error:
-// const setNotAgnosticOK = {a, b};
-//                          ^
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:25:30: Context: Constant value is not strong/weak mode agnostic.
-// const setNotAgnosticOK = {a, b};
-//                              ^
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:25:7: Context: While analyzing:
-// const setNotAgnosticOK = {a, b};
-//       ^
-//
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:31:26: Error: Constant evaluation error:
-// const mapNotAgnosticOK = {a: 0, b: 1};
-//                          ^
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:31:33: Context: Constant value is not strong/weak mode agnostic.
-// const mapNotAgnosticOK = {a: 0, b: 1};
-//                                 ^
-// pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_collections.dart:31:7: Context: While analyzing:
-// const mapNotAgnosticOK = {a: 0, b: 1};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
@@ -35,16 +15,16 @@
 static const field core::Set<core::bool> setWithUnevaluatedSpread = #C12;
 static const field core::List<core::int> a = #C13;
 static const field core::List<core::int?> b = #C14;
-static const field core::Set<core::List<core::int?>> setNotAgnosticOK = invalid-expression "Constant value is not strong/weak mode agnostic.";
-static const field invalid-type MapWithUnevaluated = #C15;
-static const field core::Map<core::List<core::int?>, core::int> mapNotAgnosticOK = invalid-expression "Constant value is not strong/weak mode agnostic.";
+static const field core::Set<core::List<core::int?>> setNotAgnosticOK = #C15;
+static const field invalid-type MapWithUnevaluated = #C16;
+static const field core::Map<core::List<core::int?>, core::int> mapNotAgnosticOK = #C19;
 static method main() → dynamic {
-  core::print(#C16);
-  core::print(#C17);
-  core::print(#C18);
-  core::print(#C19);
-  core::print(<core::String>{"hello"});
+  core::print(#C20);
   core::print(#C21);
+  core::print(#C22);
+  core::print(#C23);
+  core::print(<core::String>{"hello"});
+  core::print(#C25);
 }
 
 constants  {
@@ -62,13 +42,17 @@
   #C12 = eval #C9 + const <dynamic>{const core::bool::fromEnvironment(#C1)} + const <dynamic>{const core::bool::fromEnvironment(#C2)} + #C9 + #C11
   #C13 = <core::int>[]
   #C14 = <core::int?>[]
-  #C15 = eval const <dynamic, dynamic>{const core::bool::fromEnvironment(#C1): const core::bool::fromEnvironment(#C2)}
-  #C16 = eval const <dynamic>[const core::bool::fromEnvironment(#C1)] + const <dynamic>[const core::bool::fromEnvironment(#C2)] + #C4
-  #C17 = eval #C4 + const <dynamic>[const core::bool::fromEnvironment(#C1)] + const <dynamic>[const core::bool::fromEnvironment(#C2)] + #C4 + #C7
-  #C18 = eval const <dynamic>{const core::bool::fromEnvironment(#C1)} + const <dynamic>{const core::bool::fromEnvironment(#C2)} + #C9
-  #C19 = eval #C9 + const <dynamic>{const core::bool::fromEnvironment(#C1)} + const <dynamic>{const core::bool::fromEnvironment(#C2)} + #C9 + #C11
-  #C20 = "hello"
-  #C21 = <core::String>{#C20}
+  #C15 = <core::List<core::int?>>{#C13, #C14}
+  #C16 = eval const <dynamic, dynamic>{const core::bool::fromEnvironment(#C1): const core::bool::fromEnvironment(#C2)}
+  #C17 = 0
+  #C18 = 1
+  #C19 = <core::List<core::int?>, core::int>{#C13:#C17, #C14:#C18)
+  #C20 = eval const <dynamic>[const core::bool::fromEnvironment(#C1)] + const <dynamic>[const core::bool::fromEnvironment(#C2)] + #C4
+  #C21 = eval #C4 + const <dynamic>[const core::bool::fromEnvironment(#C1)] + const <dynamic>[const core::bool::fromEnvironment(#C2)] + #C4 + #C7
+  #C22 = eval const <dynamic>{const core::bool::fromEnvironment(#C1)} + const <dynamic>{const core::bool::fromEnvironment(#C2)} + #C9
+  #C23 = eval #C9 + const <dynamic>{const core::bool::fromEnvironment(#C1)} + const <dynamic>{const core::bool::fromEnvironment(#C2)} + #C9 + #C11
+  #C24 = "hello"
+  #C25 = <core::String>{#C24}
 }
 
 Extra constant evaluation status:
diff --git a/pkg/front_end/testcases/general/export_test.dart.strong.expect b/pkg/front_end/testcases/general/export_test.dart.strong.expect
index 8dbe328..497ce03 100644
--- a/pkg/front_end/testcases/general/export_test.dart.strong.expect
+++ b/pkg/front_end/testcases/general/export_test.dart.strong.expect
@@ -1,12 +1,15 @@
 library;
 import self as self;
 import "dart:core" as core;
-import "dart:developer" as dev;
 additionalExports = (core::print)
 
 import "dart:developer" show UserTag;
 export "dart:core" show print;
 
 static method main() → dynamic {
-  core::print(dev::UserTag*);
+  core::print(#C1);
+}
+
+constants  {
+  #C1 = TypeLiteralConstant(dev::UserTag*)
 }
diff --git a/pkg/front_end/testcases/general/export_test.dart.strong.transformed.expect b/pkg/front_end/testcases/general/export_test.dart.strong.transformed.expect
index 0676de4..497ce03 100644
--- a/pkg/front_end/testcases/general/export_test.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/export_test.dart.strong.transformed.expect
@@ -1,17 +1,15 @@
 library;
 import self as self;
 import "dart:core" as core;
-import "dart:developer" as dev;
 additionalExports = (core::print)
 
 import "dart:developer" show UserTag;
 export "dart:core" show print;
 
 static method main() → dynamic {
-  core::print(dev::UserTag*);
+  core::print(#C1);
 }
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///export_test.dart:14:9 -> TypeLiteralConstant(UserTag*)
-Extra constant evaluation: evaluated: 2, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(dev::UserTag*)
+}
diff --git a/pkg/front_end/testcases/general/expressions.dart.strong.expect b/pkg/front_end/testcases/general/expressions.dart.strong.expect
index 1fcb0bc..5cb0aef 100644
--- a/pkg/front_end/testcases/general/expressions.dart.strong.expect
+++ b/pkg/front_end/testcases/general/expressions.dart.strong.expect
@@ -72,9 +72,9 @@
   self::caller(({dynamic x = #C1}) → Null {
     core::print("<anon> was called with ${x}");
   });
-  core::print(core::int*.{core::Type::toString}());
-  core::print(core::int*);
-  core::print(let final core::Type* #t5 = core::int* in block {
+  core::print((#C3).{core::Type::toString}());
+  core::print(#C3);
+  core::print(let final core::Type* #t5 = #C3 in block {
     #t5.{core::Type::toString}();
   } =>#t5);
   try {
@@ -92,6 +92,7 @@
 constants  {
   #C1 = null
   #C2 = core::Object {}
+  #C3 = TypeLiteralConstant(core::int*)
 }
 
 
diff --git a/pkg/front_end/testcases/general/expressions.dart.strong.transformed.expect b/pkg/front_end/testcases/general/expressions.dart.strong.transformed.expect
index d23becc..0e8e94f 100644
--- a/pkg/front_end/testcases/general/expressions.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/expressions.dart.strong.transformed.expect
@@ -72,9 +72,9 @@
   self::caller(({dynamic x = #C1}) → Null {
     core::print("<anon> was called with ${x}");
   });
-  core::print(core::int*.{core::Type::toString}());
-  core::print(core::int*);
-  core::print(let final core::Type* #t5 = core::int* in block {
+  core::print((#C3).{core::Type::toString}());
+  core::print(#C3);
+  core::print(let final core::Type* #t5 = #C3 in block {
     #t5.{core::Type::toString}();
   } =>#t5);
   try {
@@ -92,16 +92,14 @@
 constants  {
   #C1 = null
   #C2 = core::Object {}
+  #C3 = TypeLiteralConstant(core::int*)
 }
 
 Extra constant evaluation status:
 Evaluated: StringConcatenation @ org-dartlang-testcase:///expressions.dart:21:8 -> StringConstant("foobar")
-Evaluated: TypeLiteral @ org-dartlang-testcase:///expressions.dart:70:10 -> TypeLiteralConstant(int*)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///expressions.dart:71:9 -> TypeLiteralConstant(int*)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///expressions.dart:72:9 -> TypeLiteralConstant(int*)
 Evaluated: VariableGetImpl @ org-dartlang-testcase:///expressions.dart:72:9 -> TypeLiteralConstant(int*)
 Evaluated: VariableGet @ org-dartlang-testcase:///expressions.dart:72:9 -> TypeLiteralConstant(int*)
-Extra constant evaluation: evaluated: 138, effectively constant: 6
+Extra constant evaluation: evaluated: 135, effectively constant: 3
 
 
 Constructor coverage from constants:
diff --git a/pkg/front_end/testcases/general/issue42997.dart.strong.expect b/pkg/front_end/testcases/general/issue42997.dart.strong.expect
index 40813a7..cfae480 100644
--- a/pkg/front_end/testcases/general/issue42997.dart.strong.expect
+++ b/pkg/front_end/testcases/general/issue42997.dart.strong.expect
@@ -57,7 +57,7 @@
   method dispose() → void {
     for (final dynamic #t1 = invalid-expression "pkg/front_end/testcases/general/issue42997.dart:12:10: Error: Can't use 'PropertyState' because it is declared more than once.
     for (PropertyState<Object, Object>> state in _states) ;
-         ^".<(core::Object*); invalid-expression "pkg/front_end/testcases/general/issue42997.dart:12:30: Error: This couldn't be parsed.
+         ^".<(#C1); invalid-expression "pkg/front_end/testcases/general/issue42997.dart:12:30: Error: This couldn't be parsed.
     for (PropertyState<Object, Object>> state in _states) ;
                              ^" as{TypeError,ForDynamic} core::bool*; invalid-expression "pkg/front_end/testcases/general/issue42997.dart:12:30: Error: This couldn't be parsed.
     for (PropertyState<Object, Object>> state in _states) ;
@@ -81,3 +81,7 @@
 }
 static method main() → dynamic {}
 static abstract method PropertyState() → dynamic;
+
+constants  {
+  #C1 = TypeLiteralConstant(core::Object*)
+}
diff --git a/pkg/front_end/testcases/general/issue42997.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue42997.dart.strong.transformed.expect
index b501d6e..96d6a7c 100644
--- a/pkg/front_end/testcases/general/issue42997.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/issue42997.dart.strong.transformed.expect
@@ -57,7 +57,7 @@
   method dispose() → void {
     for (final dynamic #t1 = invalid-expression "pkg/front_end/testcases/general/issue42997.dart:12:10: Error: Can't use 'PropertyState' because it is declared more than once.
     for (PropertyState<Object, Object>> state in _states) ;
-         ^".<(core::Object*); invalid-expression "pkg/front_end/testcases/general/issue42997.dart:12:30: Error: This couldn't be parsed.
+         ^".<(#C1); invalid-expression "pkg/front_end/testcases/general/issue42997.dart:12:30: Error: This couldn't be parsed.
     for (PropertyState<Object, Object>> state in _states) ;
                              ^"; invalid-expression "pkg/front_end/testcases/general/issue42997.dart:12:30: Error: This couldn't be parsed.
     for (PropertyState<Object, Object>> state in _states) ;
@@ -82,7 +82,6 @@
 static method main() → dynamic {}
 static abstract method PropertyState() → dynamic;
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///issue42997.dart:12:24 -> TypeLiteralConstant(Object*)
-Extra constant evaluation: evaluated: 2, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(core::Object*)
+}
diff --git a/pkg/front_end/testcases/general/type_variable_uses.dart.strong.expect b/pkg/front_end/testcases/general/type_variable_uses.dart.strong.expect
index 97634b7..fe9dcbd 100644
--- a/pkg/front_end/testcases/general/type_variable_uses.dart.strong.expect
+++ b/pkg/front_end/testcases/general/type_variable_uses.dart.strong.expect
@@ -70,13 +70,13 @@
     : super core::Object::•()
     ;
   static method staticMethod() → self::C<dynamic>* {
-    core::print(invalid-type);
+    core::print(#C1);
     invalid-type t;
     self::C<invalid-type>* l;
     self::C<self::C<invalid-type>*>* ll;
-    #C1;
     #C2;
     #C3;
+    #C4;
     #C5;
     #C6;
   }
@@ -85,9 +85,9 @@
     self::C::T* t;
     self::C<self::C::T*>* l;
     self::C<self::C<self::C::T*>*>* ll;
-    #C1;
     #C2;
     #C3;
+    #C4;
     #C5;
     #C6;
   }
@@ -105,12 +105,12 @@
 static method main() → dynamic {}
 
 constants  {
-  #C1 = self::C<invalid-type> {}
-  #C2 = <invalid-type>[]
-  #C3 = <self::C<invalid-type>*>[]
-  #C4 = TypeLiteralConstant(invalid-type)
-  #C5 = <core::Object*>[#C4]
-  #C6 = <core::Object*>[#C1]
+  #C1 = TypeLiteralConstant(invalid-type)
+  #C2 = self::C<invalid-type> {}
+  #C3 = <invalid-type>[]
+  #C4 = <self::C<invalid-type>*>[]
+  #C5 = <core::Object*>[#C1]
+  #C6 = <core::Object*>[#C2]
 }
 
 
diff --git a/pkg/front_end/testcases/general/type_variable_uses.dart.strong.transformed.expect b/pkg/front_end/testcases/general/type_variable_uses.dart.strong.transformed.expect
index e2cf292..fe9dcbd 100644
--- a/pkg/front_end/testcases/general/type_variable_uses.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/type_variable_uses.dart.strong.transformed.expect
@@ -70,13 +70,13 @@
     : super core::Object::•()
     ;
   static method staticMethod() → self::C<dynamic>* {
-    core::print(invalid-type);
+    core::print(#C1);
     invalid-type t;
     self::C<invalid-type>* l;
     self::C<self::C<invalid-type>*>* ll;
-    #C1;
     #C2;
     #C3;
+    #C4;
     #C5;
     #C6;
   }
@@ -85,9 +85,9 @@
     self::C::T* t;
     self::C<self::C::T*>* l;
     self::C<self::C<self::C::T*>*>* ll;
-    #C1;
     #C2;
     #C3;
+    #C4;
     #C5;
     #C6;
   }
@@ -105,18 +105,14 @@
 static method main() → dynamic {}
 
 constants  {
-  #C1 = self::C<invalid-type> {}
-  #C2 = <invalid-type>[]
-  #C3 = <self::C<invalid-type>*>[]
-  #C4 = TypeLiteralConstant(invalid-type)
-  #C5 = <core::Object*>[#C4]
-  #C6 = <core::Object*>[#C1]
+  #C1 = TypeLiteralConstant(invalid-type)
+  #C2 = self::C<invalid-type> {}
+  #C3 = <invalid-type>[]
+  #C4 = <self::C<invalid-type>*>[]
+  #C5 = <core::Object*>[#C1]
+  #C6 = <core::Object*>[#C2]
 }
 
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///type_variable_uses.dart:8:11 -> TypeLiteralConstant(<invalid>)
-Extra constant evaluation: evaluated: 4, effectively constant: 1
-
 
 Constructor coverage from constants:
 org-dartlang-testcase:///type_variable_uses.dart:
diff --git a/pkg/front_end/testcases/general/with_dependencies/variance_from_dill/variance_from_dill.dart.strong.expect b/pkg/front_end/testcases/general/with_dependencies/variance_from_dill/variance_from_dill.dart.strong.expect
index 663835f..8283fbb 100644
--- a/pkg/front_end/testcases/general/with_dependencies/variance_from_dill/variance_from_dill.dart.strong.expect
+++ b/pkg/front_end/testcases/general/with_dependencies/variance_from_dill/variance_from_dill.dart.strong.expect
@@ -6,7 +6,7 @@
 
 typedef G<unrelated T extends core::Object* = dynamic> = (() →* dynamic) →* dynamic;
 static method main() → dynamic {
-  core::print((() →* dynamic) →* dynamic);
+  core::print(#C1);
 }
 
 library;
@@ -14,3 +14,7 @@
 import "dart:core" as core;
 
 typedef F<unrelated T extends core::Object* = dynamic> = () →* dynamic;
+
+constants  {
+  #C1 = TypeLiteralConstant((() →* dynamic) →* dynamic)
+}
diff --git a/pkg/front_end/testcases/general/with_dependencies/variance_from_dill/variance_from_dill.dart.strong.transformed.expect b/pkg/front_end/testcases/general/with_dependencies/variance_from_dill/variance_from_dill.dart.strong.transformed.expect
index 749e9d0..8283fbb 100644
--- a/pkg/front_end/testcases/general/with_dependencies/variance_from_dill/variance_from_dill.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/with_dependencies/variance_from_dill/variance_from_dill.dart.strong.transformed.expect
@@ -6,7 +6,7 @@
 
 typedef G<unrelated T extends core::Object* = dynamic> = (() →* dynamic) →* dynamic;
 static method main() → dynamic {
-  core::print((() →* dynamic) →* dynamic);
+  core::print(#C1);
 }
 
 library;
@@ -15,7 +15,6 @@
 
 typedef F<unrelated T extends core::Object* = dynamic> = () →* dynamic;
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///variance_from_dill.dart:5:9 -> TypeLiteralConstant(dynamic Function(dynamic Function()*)*)
-Extra constant evaluation: evaluated: 2, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant((() →* dynamic) →* dynamic)
+}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/bug33099.dart.weak.expect b/pkg/front_end/testcases/general_nnbd_opt_out/bug33099.dart.weak.expect
index 491a29a..9b4bb6a 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/bug33099.dart.weak.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/bug33099.dart.weak.expect
@@ -61,9 +61,9 @@
 }
 static const field self::_FailingTest* failingTest = #C1;
 static method main() → dynamic {
-  mir::ClassMirror* classMirror = mir::reflectClass(self::MyTest2*);
+  mir::ClassMirror* classMirror = mir::reflectClass(#C2);
   classMirror.{mir::ClassMirror::instanceMembers}.{core::Map::forEach}((core::Symbol* symbol, mir::MethodMirror* memberMirror) → Null {
-    if(memberMirror.{mir::DeclarationMirror::simpleName}.{core::Symbol::==}(#C2)) {
+    if(memberMirror.{mir::DeclarationMirror::simpleName}.{core::Symbol::==}(#C3)) {
       core::print(memberMirror);
       core::print(self::_hasFailingTestAnnotation(memberMirror));
     }
@@ -82,7 +82,8 @@
 
 constants  {
   #C1 = self::_FailingTest {}
-  #C2 = #foo
+  #C2 = TypeLiteralConstant(self::MyTest2*)
+  #C3 = #foo
 }
 
 
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/bug33099.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/bug33099.dart.weak.transformed.expect
index a381949..bb18f32 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/bug33099.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/bug33099.dart.weak.transformed.expect
@@ -61,9 +61,9 @@
 }
 static const field self::_FailingTest* failingTest = #C1;
 static method main() → dynamic {
-  mir::ClassMirror* classMirror = mir::reflectClass(self::MyTest2*);
+  mir::ClassMirror* classMirror = mir::reflectClass(#C2);
   classMirror.{mir::ClassMirror::instanceMembers}.{core::Map::forEach}((core::Symbol* symbol, mir::MethodMirror* memberMirror) → Null {
-    if(memberMirror.{mir::DeclarationMirror::simpleName}.{core::Symbol::==}(#C2)) {
+    if(memberMirror.{mir::DeclarationMirror::simpleName}.{core::Symbol::==}(#C3)) {
       core::print(memberMirror);
       core::print(self::_hasFailingTestAnnotation(memberMirror));
     }
@@ -82,13 +82,10 @@
 
 constants  {
   #C1 = self::_FailingTest {}
-  #C2 = #foo
+  #C2 = TypeLiteralConstant(self::MyTest2*)
+  #C3 = #foo
 }
 
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///bug33099.dart:23:42 -> TypeLiteralConstant(MyTest2*)
-Extra constant evaluation: evaluated: 33, effectively constant: 1
-
 
 Constructor coverage from constants:
 org-dartlang-testcase:///bug33099.dart:
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/check_deferred_read_type.dart.weak.expect b/pkg/front_end/testcases/general_nnbd_opt_out/check_deferred_read_type.dart.weak.expect
index b3ae2c0..efb9d56 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/check_deferred_read_type.dart.weak.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/check_deferred_read_type.dart.weak.expect
@@ -1,22 +1,21 @@
 library;
 import self as self;
 import "dart:core" as core;
-import "deferred_lib.dart" as def;
 
 import "org-dartlang-testcase:///deferred_lib.dart" deferred as lib;
 
 static method main() → dynamic {}
 static method test() → dynamic {
-  core::print(let final dynamic #t1 = CheckLibraryIsLoaded(lib) in def::C*);
+  core::print(let final dynamic #t1 = CheckLibraryIsLoaded(lib) in #C1);
 }
 
 library;
-import self as def;
+import self as self2;
 import "dart:core" as core;
 
 class C extends core::Object {
   static field core::int* y = 1;
-  synthetic constructor •() → def::C*
+  synthetic constructor •() → self2::C*
     : super core::Object::•()
     ;
   static method m() → core::int*
@@ -35,3 +34,7 @@
 static field core::int* x = 0;
 static method m(dynamic x) → dynamic
   return null;
+
+constants  {
+  #C1 = TypeLiteralConstant(self2::C*)
+}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/check_deferred_read_type.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/check_deferred_read_type.dart.weak.transformed.expect
index 156d0a6..2813c9c5 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/check_deferred_read_type.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/check_deferred_read_type.dart.weak.transformed.expect
@@ -1,22 +1,21 @@
 library;
 import self as self;
 import "dart:core" as core;
-import "deferred_lib.dart" as def;
 
 import "org-dartlang-testcase:///deferred_lib.dart" deferred as lib;
 
 static method main() → dynamic {}
 static method test() → dynamic {
-  core::print(let final core::Object* #t1 = CheckLibraryIsLoaded(lib) in def::C*);
+  core::print(let final core::Object* #t1 = CheckLibraryIsLoaded(lib) in #C1);
 }
 
 library;
-import self as def;
+import self as self2;
 import "dart:core" as core;
 
 class C extends core::Object {
   static field core::int* y = 1;
-  synthetic constructor •() → def::C*
+  synthetic constructor •() → self2::C*
     : super core::Object::•()
     ;
   static method m() → core::int*
@@ -36,7 +35,6 @@
 static method m(dynamic x) → dynamic
   return null;
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///check_deferred_read_type.dart:11:13 -> TypeLiteralConstant(C*)
-Extra constant evaluation: evaluated: 4, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(self2::C*)
+}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/export_test.dart.weak.expect b/pkg/front_end/testcases/general_nnbd_opt_out/export_test.dart.weak.expect
index 8dbe328..497ce03 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/export_test.dart.weak.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/export_test.dart.weak.expect
@@ -1,12 +1,15 @@
 library;
 import self as self;
 import "dart:core" as core;
-import "dart:developer" as dev;
 additionalExports = (core::print)
 
 import "dart:developer" show UserTag;
 export "dart:core" show print;
 
 static method main() → dynamic {
-  core::print(dev::UserTag*);
+  core::print(#C1);
+}
+
+constants  {
+  #C1 = TypeLiteralConstant(dev::UserTag*)
 }
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/export_test.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/export_test.dart.weak.transformed.expect
index 405fb55..497ce03 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/export_test.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/export_test.dart.weak.transformed.expect
@@ -1,17 +1,15 @@
 library;
 import self as self;
 import "dart:core" as core;
-import "dart:developer" as dev;
 additionalExports = (core::print)
 
 import "dart:developer" show UserTag;
 export "dart:core" show print;
 
 static method main() → dynamic {
-  core::print(dev::UserTag*);
+  core::print(#C1);
 }
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///export_test.dart:16:9 -> TypeLiteralConstant(UserTag*)
-Extra constant evaluation: evaluated: 2, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(dev::UserTag*)
+}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/expressions.dart.weak.expect b/pkg/front_end/testcases/general_nnbd_opt_out/expressions.dart.weak.expect
index d29fb1b..8c295b6 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/expressions.dart.weak.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/expressions.dart.weak.expect
@@ -72,9 +72,9 @@
   self::caller(({dynamic x = #C1}) → Null {
     core::print("<anon> was called with ${x}");
   });
-  core::print(core::int*.{core::Type::toString}());
-  core::print(core::int*);
-  core::print(let final core::Type* #t5 = core::int* in block {
+  core::print((#C3).{core::Type::toString}());
+  core::print(#C3);
+  core::print(let final core::Type* #t5 = #C3 in block {
     #t5.{core::Type::toString}();
   } =>#t5);
   try {
@@ -92,6 +92,7 @@
 constants  {
   #C1 = null
   #C2 = core::Object {}
+  #C3 = TypeLiteralConstant(core::int*)
 }
 
 
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/expressions.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/expressions.dart.weak.transformed.expect
index 75e91c9..b57f1a5 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/expressions.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/expressions.dart.weak.transformed.expect
@@ -72,9 +72,9 @@
   self::caller(({dynamic x = #C1}) → Null {
     core::print("<anon> was called with ${x}");
   });
-  core::print(core::int*.{core::Type::toString}());
-  core::print(core::int*);
-  core::print(let final core::Type* #t5 = core::int* in block {
+  core::print((#C3).{core::Type::toString}());
+  core::print(#C3);
+  core::print(let final core::Type* #t5 = #C3 in block {
     #t5.{core::Type::toString}();
   } =>#t5);
   try {
@@ -92,16 +92,14 @@
 constants  {
   #C1 = null
   #C2 = core::Object {}
+  #C3 = TypeLiteralConstant(core::int*)
 }
 
 Extra constant evaluation status:
 Evaluated: StringConcatenation @ org-dartlang-testcase:///expressions.dart:23:8 -> StringConstant("foobar")
-Evaluated: TypeLiteral @ org-dartlang-testcase:///expressions.dart:72:10 -> TypeLiteralConstant(int*)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///expressions.dart:73:9 -> TypeLiteralConstant(int*)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///expressions.dart:74:9 -> TypeLiteralConstant(int*)
 Evaluated: VariableGetImpl @ org-dartlang-testcase:///expressions.dart:74:9 -> TypeLiteralConstant(int*)
 Evaluated: VariableGet @ org-dartlang-testcase:///expressions.dart:74:9 -> TypeLiteralConstant(int*)
-Extra constant evaluation: evaluated: 138, effectively constant: 6
+Extra constant evaluation: evaluated: 135, effectively constant: 3
 
 
 Constructor coverage from constants:
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
index ce1ae9d..c53e92f 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
@@ -1,3 +1,8 @@
+//
+// Problems outside component:
+//
+// third_party/pkg/ffi/lib/src/allocation.dart: Info: Support for using non-constant type arguments 'T' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type.
+//
 library;
 import self as self;
 import "dart:core" as core;
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/type_variable_uses.dart.weak.expect b/pkg/front_end/testcases/general_nnbd_opt_out/type_variable_uses.dart.weak.expect
index 32194a2..ddc2500 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/type_variable_uses.dart.weak.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/type_variable_uses.dart.weak.expect
@@ -70,13 +70,13 @@
     : super core::Object::•()
     ;
   static method staticMethod() → self::C<dynamic>* {
-    core::print(invalid-type);
+    core::print(#C1);
     invalid-type t;
     self::C<invalid-type>* l;
     self::C<self::C<invalid-type>*>* ll;
-    #C1;
     #C2;
     #C3;
+    #C4;
     #C5;
     #C6;
   }
@@ -85,9 +85,9 @@
     self::C::T* t;
     self::C<self::C::T*>* l;
     self::C<self::C<self::C::T*>*>* ll;
-    #C1;
     #C2;
     #C3;
+    #C4;
     #C5;
     #C6;
   }
@@ -105,12 +105,12 @@
 static method main() → dynamic {}
 
 constants  {
-  #C1 = self::C<invalid-type> {}
-  #C2 = <invalid-type>[]
-  #C3 = <self::C<invalid-type>*>[]
-  #C4 = TypeLiteralConstant(invalid-type)
-  #C5 = <core::Object*>[#C4]
-  #C6 = <core::Object*>[#C1]
+  #C1 = TypeLiteralConstant(invalid-type)
+  #C2 = self::C<invalid-type> {}
+  #C3 = <invalid-type>[]
+  #C4 = <self::C<invalid-type>*>[]
+  #C5 = <core::Object*>[#C1]
+  #C6 = <core::Object*>[#C2]
 }
 
 
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/type_variable_uses.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/type_variable_uses.dart.weak.transformed.expect
index e162040..ddc2500 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/type_variable_uses.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/type_variable_uses.dart.weak.transformed.expect
@@ -70,13 +70,13 @@
     : super core::Object::•()
     ;
   static method staticMethod() → self::C<dynamic>* {
-    core::print(invalid-type);
+    core::print(#C1);
     invalid-type t;
     self::C<invalid-type>* l;
     self::C<self::C<invalid-type>*>* ll;
-    #C1;
     #C2;
     #C3;
+    #C4;
     #C5;
     #C6;
   }
@@ -85,9 +85,9 @@
     self::C::T* t;
     self::C<self::C::T*>* l;
     self::C<self::C<self::C::T*>*>* ll;
-    #C1;
     #C2;
     #C3;
+    #C4;
     #C5;
     #C6;
   }
@@ -105,18 +105,14 @@
 static method main() → dynamic {}
 
 constants  {
-  #C1 = self::C<invalid-type> {}
-  #C2 = <invalid-type>[]
-  #C3 = <self::C<invalid-type>*>[]
-  #C4 = TypeLiteralConstant(invalid-type)
-  #C5 = <core::Object*>[#C4]
-  #C6 = <core::Object*>[#C1]
+  #C1 = TypeLiteralConstant(invalid-type)
+  #C2 = self::C<invalid-type> {}
+  #C3 = <invalid-type>[]
+  #C4 = <self::C<invalid-type>*>[]
+  #C5 = <core::Object*>[#C1]
+  #C6 = <core::Object*>[#C2]
 }
 
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///type_variable_uses.dart:10:11 -> TypeLiteralConstant(<invalid>)
-Extra constant evaluation: evaluated: 4, effectively constant: 1
-
 
 Constructor coverage from constants:
 org-dartlang-testcase:///type_variable_uses.dart:
diff --git a/pkg/front_end/testcases/inference/reference_to_typedef.dart.strong.expect b/pkg/front_end/testcases/inference/reference_to_typedef.dart.strong.expect
index e08b136..1c7e0ba 100644
--- a/pkg/front_end/testcases/inference/reference_to_typedef.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/reference_to_typedef.dart.strong.expect
@@ -3,5 +3,9 @@
 import "dart:core" as core;
 
 typedef F = () →* void;
-static final field core::Type* x = () →* void;
+static final field core::Type* x = #C1;
 static method main() → dynamic {}
+
+constants  {
+  #C1 = TypeLiteralConstant(() →* void)
+}
diff --git a/pkg/front_end/testcases/inference/reference_to_typedef.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/reference_to_typedef.dart.strong.transformed.expect
index 1892d0c..1c7e0ba 100644
--- a/pkg/front_end/testcases/inference/reference_to_typedef.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/reference_to_typedef.dart.strong.transformed.expect
@@ -3,10 +3,9 @@
 import "dart:core" as core;
 
 typedef F = () →* void;
-static final field core::Type* x = () →* void;
+static final field core::Type* x = #C1;
 static method main() → dynamic {}
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///reference_to_typedef.dart:9:11 -> TypeLiteralConstant(void Function()*)
-Extra constant evaluation: evaluated: 1, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(() →* void)
+}
diff --git a/pkg/front_end/testcases/nnbd/const_canonical_type.dart b/pkg/front_end/testcases/nnbd/const_canonical_type.dart
new file mode 100644
index 0000000..28029ab
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/const_canonical_type.dart
@@ -0,0 +1,84 @@
+// 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.
+
+import 'dart:async';
+
+class Check {
+  final _ignored;
+
+  const Check(x, y)
+      : assert(identical(x, y)),
+      _ignored = identical(x, y) ? 42 : 1 ~/ 0;
+}
+
+void expectEqual(x, y) {
+  if (x != y) {
+    throw "Arguments were supposed to be identical.";
+  }
+}
+
+class A<X> {
+  const A();
+}
+
+typedef F1 = A<FutureOr<dynamic>> Function();
+typedef F2 = A<dynamic> Function();
+typedef F3 = A<FutureOr<FutureOr<dynamic>?>> Function();
+typedef F4 = A Function();
+
+test1() {
+  const c = A;
+  var v = A;
+
+  expectEqual(c, c);
+  expectEqual(c, A);
+  expectEqual(A, A);
+  expectEqual(v, v);
+  expectEqual(v, A);
+
+  const cf1 = F1;
+  const cf2 = F2;
+  const cf3 = F3;
+  const cf4 = F4;
+  var vf1 = F1;
+  var vf2 = F2;
+  var vf3 = F3;
+  var vf4 = F4;
+
+  expectEqual(cf1, cf2);
+  expectEqual(cf2, cf3);
+  expectEqual(cf3, cf4);
+  expectEqual(cf4, vf1);
+  expectEqual(vf1, vf2);
+  expectEqual(vf2, vf3);
+  expectEqual(vf3, vf4);
+
+  const a1 = A<List<F1>>();
+  const a2 = A<List<F2>>();
+  const a3 = A<List<F3>>();
+  const a4 = A<List<F4>>();
+
+  return const <dynamic>[
+    Check(c, c),
+    Check(c, A),
+    Check(A, A),
+
+    Check(cf1, cf2),
+    Check(cf2, cf3),
+    Check(cf3, cf4),
+
+    Check(a1, a2),
+    Check(a2, a3),
+    Check(a3, a4),
+    Check(a4, const A<List<F1>>()),
+    Check(const A<List<F1>>(), const A<List<F2>>()),
+    Check(const A<List<F2>>(), const A<List<F3>>()),
+    Check(const A<List<F3>>(), const A<List<F4>>()),
+    Check(const A<List<F4>>(), a1),
+  ];
+}
+
+main() {
+  test1();
+}
diff --git a/pkg/front_end/testcases/nnbd/const_canonical_type.dart.outline.expect b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.outline.expect
new file mode 100644
index 0000000..5239ad1
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.outline.expect
@@ -0,0 +1,27 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "dart:async";
+
+typedef F1 = () → self::A<FutureOr<dynamic>>;
+typedef F2 = () → self::A<dynamic>;
+typedef F3 = () → self::A<FutureOr<FutureOr<dynamic>?>>;
+typedef F4 = () → self::A<dynamic>;
+class Check extends core::Object /*hasConstConstructor*/  {
+  final field dynamic _ignored;
+  const constructor •(dynamic x, dynamic y) → self::Check
+    : assert(core::identical(x, y)), self::Check::_ignored = core::identical(x, y) ?{core::int} 42 : 1.{core::num::~/}(0), super core::Object::•()
+    ;
+}
+class A<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/  {
+  const constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+static method expectEqual(dynamic x, dynamic y) → void
+  ;
+static method test1() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/const_canonical_type.dart.strong.expect b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.strong.expect
new file mode 100644
index 0000000..1631d801
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.strong.expect
@@ -0,0 +1,64 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "dart:async";
+
+typedef F1 = () → self::A<FutureOr<dynamic>>;
+typedef F2 = () → self::A<dynamic>;
+typedef F3 = () → self::A<FutureOr<FutureOr<dynamic>?>>;
+typedef F4 = () → self::A<dynamic>;
+class Check extends core::Object /*hasConstConstructor*/  {
+  final field dynamic _ignored;
+  const constructor •(dynamic x, dynamic y) → self::Check
+    : assert(core::identical(x, y)), self::Check::_ignored = core::identical(x, y) ?{core::int} 42 : 1.{core::num::~/}(0), super core::Object::•()
+    ;
+}
+class A<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/  {
+  const constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+static method expectEqual(dynamic x, dynamic y) → void {
+  if(!x.{core::Object::==}(y)) {
+    throw "Arguments were supposed to be identical.";
+  }
+}
+static method test1() → dynamic {
+  core::Type v = #C1;
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(v, v);
+  self::expectEqual(v, #C1);
+  core::Type vf1 = #C2;
+  core::Type vf2 = #C2;
+  core::Type vf3 = #C2;
+  core::Type vf4 = #C2;
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, vf1);
+  self::expectEqual(vf1, vf2);
+  self::expectEqual(vf2, vf3);
+  self::expectEqual(vf3, vf4);
+  return #C5;
+}
+static method main() → dynamic {
+  self::test1();
+}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::A<dynamic>)
+  #C2 = TypeLiteralConstant(() → self::A<dynamic>)
+  #C3 = 42
+  #C4 = self::Check {_ignored:#C3}
+  #C5 = <dynamic>[#C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_canonical_type.dart:
+- A. (from org-dartlang-testcase:///const_canonical_type.dart:22:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- Check. (from org-dartlang-testcase:///const_canonical_type.dart:10:9)
diff --git a/pkg/front_end/testcases/nnbd/const_canonical_type.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.strong.transformed.expect
new file mode 100644
index 0000000..1631d801
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.strong.transformed.expect
@@ -0,0 +1,64 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "dart:async";
+
+typedef F1 = () → self::A<FutureOr<dynamic>>;
+typedef F2 = () → self::A<dynamic>;
+typedef F3 = () → self::A<FutureOr<FutureOr<dynamic>?>>;
+typedef F4 = () → self::A<dynamic>;
+class Check extends core::Object /*hasConstConstructor*/  {
+  final field dynamic _ignored;
+  const constructor •(dynamic x, dynamic y) → self::Check
+    : assert(core::identical(x, y)), self::Check::_ignored = core::identical(x, y) ?{core::int} 42 : 1.{core::num::~/}(0), super core::Object::•()
+    ;
+}
+class A<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/  {
+  const constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+static method expectEqual(dynamic x, dynamic y) → void {
+  if(!x.{core::Object::==}(y)) {
+    throw "Arguments were supposed to be identical.";
+  }
+}
+static method test1() → dynamic {
+  core::Type v = #C1;
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(v, v);
+  self::expectEqual(v, #C1);
+  core::Type vf1 = #C2;
+  core::Type vf2 = #C2;
+  core::Type vf3 = #C2;
+  core::Type vf4 = #C2;
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, vf1);
+  self::expectEqual(vf1, vf2);
+  self::expectEqual(vf2, vf3);
+  self::expectEqual(vf3, vf4);
+  return #C5;
+}
+static method main() → dynamic {
+  self::test1();
+}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::A<dynamic>)
+  #C2 = TypeLiteralConstant(() → self::A<dynamic>)
+  #C3 = 42
+  #C4 = self::Check {_ignored:#C3}
+  #C5 = <dynamic>[#C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_canonical_type.dart:
+- A. (from org-dartlang-testcase:///const_canonical_type.dart:22:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- Check. (from org-dartlang-testcase:///const_canonical_type.dart:10:9)
diff --git a/pkg/front_end/testcases/nnbd/const_canonical_type.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.textual_outline.expect
new file mode 100644
index 0000000..9d7cc05
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.textual_outline.expect
@@ -0,0 +1,21 @@
+import 'dart:async';
+
+class Check {
+  final _ignored;
+  const Check(x, y)
+      : assert(identical(x, y)),
+        _ignored = identical(x, y) ? 42 : 1 ~/ 0;
+}
+
+void expectEqual(x, y) {}
+
+class A<X> {
+  const A();
+}
+
+typedef F1 = A<FutureOr<dynamic>> Function();
+typedef F2 = A<dynamic> Function();
+typedef F3 = A<FutureOr<FutureOr<dynamic>?>> Function();
+typedef F4 = A Function();
+test1() {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/const_canonical_type.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..cfadbda
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.textual_outline_modelled.expect
@@ -0,0 +1,20 @@
+import 'dart:async';
+
+class A<X> {
+  const A();
+}
+
+class Check {
+  const Check(x, y)
+      : assert(identical(x, y)),
+        _ignored = identical(x, y) ? 42 : 1 ~/ 0;
+  final _ignored;
+}
+
+main() {}
+test1() {}
+typedef F1 = A<FutureOr<dynamic>> Function();
+typedef F2 = A<dynamic> Function();
+typedef F3 = A<FutureOr<FutureOr<dynamic>?>> Function();
+typedef F4 = A Function();
+void expectEqual(x, y) {}
diff --git a/pkg/front_end/testcases/nnbd/const_canonical_type.dart.weak.expect b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.weak.expect
new file mode 100644
index 0000000..43eae4f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.weak.expect
@@ -0,0 +1,64 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "dart:async";
+
+typedef F1 = () → self::A<FutureOr<dynamic>>;
+typedef F2 = () → self::A<dynamic>;
+typedef F3 = () → self::A<FutureOr<FutureOr<dynamic>?>>;
+typedef F4 = () → self::A<dynamic>;
+class Check extends core::Object /*hasConstConstructor*/  {
+  final field dynamic _ignored;
+  const constructor •(dynamic x, dynamic y) → self::Check
+    : assert(core::identical(x, y)), self::Check::_ignored = core::identical(x, y) ?{core::int} 42 : 1.{core::num::~/}(0), super core::Object::•()
+    ;
+}
+class A<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/  {
+  const constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+static method expectEqual(dynamic x, dynamic y) → void {
+  if(!x.{core::Object::==}(y)) {
+    throw "Arguments were supposed to be identical.";
+  }
+}
+static method test1() → dynamic {
+  core::Type v = #C1;
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(v, v);
+  self::expectEqual(v, #C1);
+  core::Type vf1 = #C2;
+  core::Type vf2 = #C2;
+  core::Type vf3 = #C2;
+  core::Type vf4 = #C2;
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, vf1);
+  self::expectEqual(vf1, vf2);
+  self::expectEqual(vf2, vf3);
+  self::expectEqual(vf3, vf4);
+  return #C5;
+}
+static method main() → dynamic {
+  self::test1();
+}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::A<dynamic>*)
+  #C2 = TypeLiteralConstant(() →* self::A<dynamic>*)
+  #C3 = 42
+  #C4 = self::Check {_ignored:#C3}
+  #C5 = <dynamic>[#C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_canonical_type.dart:
+- A. (from org-dartlang-testcase:///const_canonical_type.dart:22:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- Check. (from org-dartlang-testcase:///const_canonical_type.dart:10:9)
diff --git a/pkg/front_end/testcases/nnbd/const_canonical_type.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.weak.transformed.expect
new file mode 100644
index 0000000..43eae4f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/const_canonical_type.dart.weak.transformed.expect
@@ -0,0 +1,64 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "dart:async";
+
+typedef F1 = () → self::A<FutureOr<dynamic>>;
+typedef F2 = () → self::A<dynamic>;
+typedef F3 = () → self::A<FutureOr<FutureOr<dynamic>?>>;
+typedef F4 = () → self::A<dynamic>;
+class Check extends core::Object /*hasConstConstructor*/  {
+  final field dynamic _ignored;
+  const constructor •(dynamic x, dynamic y) → self::Check
+    : assert(core::identical(x, y)), self::Check::_ignored = core::identical(x, y) ?{core::int} 42 : 1.{core::num::~/}(0), super core::Object::•()
+    ;
+}
+class A<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/  {
+  const constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+static method expectEqual(dynamic x, dynamic y) → void {
+  if(!x.{core::Object::==}(y)) {
+    throw "Arguments were supposed to be identical.";
+  }
+}
+static method test1() → dynamic {
+  core::Type v = #C1;
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(#C1, #C1);
+  self::expectEqual(v, v);
+  self::expectEqual(v, #C1);
+  core::Type vf1 = #C2;
+  core::Type vf2 = #C2;
+  core::Type vf3 = #C2;
+  core::Type vf4 = #C2;
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, vf1);
+  self::expectEqual(vf1, vf2);
+  self::expectEqual(vf2, vf3);
+  self::expectEqual(vf3, vf4);
+  return #C5;
+}
+static method main() → dynamic {
+  self::test1();
+}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::A<dynamic>*)
+  #C2 = TypeLiteralConstant(() →* self::A<dynamic>*)
+  #C3 = 42
+  #C4 = self::Check {_ignored:#C3}
+  #C5 = <dynamic>[#C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_canonical_type.dart:
+- A. (from org-dartlang-testcase:///const_canonical_type.dart:22:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- Check. (from org-dartlang-testcase:///const_canonical_type.dart:10:9)
diff --git a/pkg/front_end/testcases/nnbd/constant_null_is.dart b/pkg/front_end/testcases/nnbd/constant_null_is.dart
index bdbd2fd..e252cca 100644
--- a/pkg/front_end/testcases/nnbd/constant_null_is.dart
+++ b/pkg/front_end/testcases/nnbd/constant_null_is.dart
@@ -20,7 +20,7 @@
 const c11 = null is FutureOr<Never?>;
 const c12 = null is FutureOr<Never>?;
 const e1 = const Class<int>.constructor1(null);
-const e2 = const Class<int?>.constructor1(null);
+const e2 = const Class<List<int>>.constructor1(<Null>[null]);
 const e3 = const Class<Null>.constructor1(null);
 const e4 = const Class<int>.constructor2(null);
 const e5 = const Class<int?>.constructor2(null);
@@ -59,15 +59,17 @@
       "Class<int>.constructor1(null).field");
   expect(true, new Class<int?>.constructor1(null).field,
       "new Class<int?>.constructor1(null).field");
-  // const Class<int?> is evaluated as const Class<int*> in weak mode:
-  expect(!isWeakMode, e2.field, "const Class<int?>.constructor1(null).field");
+  // const Class<List<int>> is evaluated as const Class<List<int*>*> in weak
+  // mode:
+  expect(isWeakMode, e2.field,
+      "const Class<List<int>>.constructor1(<Null>[null]).field");
   expect(new Class<Null>.constructor1(null).field, e3.field,
       "Class<Null>.constructor1(null).field");
   expect(new Class<int>.constructor2(null).field, e4.field,
       "Class<int>.constructor2(null).field");
   expect(true, new Class<int?>.constructor2(null).field,
       "new Class<int?>.constructor2(null).field");
-  // const Class<int?> is evaluated as const Class<int*> in weak mode:
+  // const Class<int?> is evaluated as const Class<int?> in weak mode:
   expect(new Class<int?>.constructor2(null).field, e5.field,
       "Class<int?>.constructor2(null).field");
   expect(new Class<Null>.constructor2(null).field, e6.field,
diff --git a/pkg/front_end/testcases/nnbd/constant_null_is.dart.outline.expect b/pkg/front_end/testcases/nnbd/constant_null_is.dart.outline.expect
index 02239ae..b6390e6 100644
--- a/pkg/front_end/testcases/nnbd/constant_null_is.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/constant_null_is.dart.outline.expect
@@ -34,7 +34,7 @@
 static const field core::bool c11 = null is{ForNonNullableByDefault} FutureOr<Never?>;
 static const field core::bool c12 = null is{ForNonNullableByDefault} FutureOr<Never>?;
 static const field self::Class<core::int> e1 = const self::Class::constructor1<core::int>(null);
-static const field self::Class<core::int?> e2 = const self::Class::constructor1<core::int?>(null);
+static const field self::Class<core::List<core::int>> e2 = const self::Class::constructor1<core::List<core::int>>(const <Null>[null]);
 static const field self::Class<Null> e3 = const self::Class::constructor1<Null>(null);
 static const field self::Class<core::int> e4 = const self::Class::constructor2<core::int>(null);
 static const field self::Class<core::int?> e5 = const self::Class::constructor2<core::int?>(null);
@@ -66,7 +66,7 @@
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is.dart:20:18 -> BoolConstant(true)
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is.dart:21:18 -> BoolConstant(true)
 Evaluated: ConstructorInvocation @ org-dartlang-testcase:///constant_null_is.dart:22:18 -> InstanceConstant(const Class<int>{Class.field: false})
-Evaluated: ConstructorInvocation @ org-dartlang-testcase:///constant_null_is.dart:23:18 -> InstanceConstant(const Class<int?>{Class.field: true})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///constant_null_is.dart:23:18 -> InstanceConstant(const Class<List<int>>{Class.field: false})
 Evaluated: ConstructorInvocation @ org-dartlang-testcase:///constant_null_is.dart:24:18 -> InstanceConstant(const Class<Null>{Class.field: true})
 Evaluated: ConstructorInvocation @ org-dartlang-testcase:///constant_null_is.dart:25:18 -> InstanceConstant(const Class<int>{Class.field: true})
 Evaluated: ConstructorInvocation @ org-dartlang-testcase:///constant_null_is.dart:26:18 -> InstanceConstant(const Class<int?>{Class.field: true})
diff --git a/pkg/front_end/testcases/nnbd/constant_null_is.dart.strong.expect b/pkg/front_end/testcases/nnbd/constant_null_is.dart.strong.expect
index e8a8746..6432e62 100644
--- a/pkg/front_end/testcases/nnbd/constant_null_is.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/constant_null_is.dart.strong.expect
@@ -34,16 +34,16 @@
 static const field core::bool c11 = #C2;
 static const field core::bool c12 = #C2;
 static const field self::Class<core::int> e1 = #C4;
-static const field self::Class<core::int?> e2 = #C5;
+static const field self::Class<core::List<core::int>> e2 = #C5;
 static const field self::Class<Null> e3 = #C6;
 static const field self::Class<core::int> e4 = #C7;
-static const field self::Class<core::int?> e5 = #C5;
+static const field self::Class<core::int?> e5 = #C8;
 static const field self::Class<Null> e6 = #C6;
 static const field self::Class<core::int> e7 = #C4;
-static const field self::Class<core::int?> e8 = #C8;
-static const field self::Class<Null> e9 = #C9;
+static const field self::Class<core::int?> e8 = #C9;
+static const field self::Class<Null> e9 = #C10;
 static const field self::Class<core::int> e10 = #C7;
-static const field self::Class<core::int?> e11 = #C5;
+static const field self::Class<core::int?> e11 = #C8;
 static const field self::Class<Null> e12 = #C6;
 static method main() → dynamic {
   self::expect(null is{ForNonNullableByDefault} core::int?, #C2, "null is int?");
@@ -61,18 +61,18 @@
   self::expect(null is{ForNonNullableByDefault} FutureOr<Never>?, #C2, "null is FutureOr<Never>?");
   self::expect(new self::Class::constructor1<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor1(null).field");
   self::expect(true, new self::Class::constructor1<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor1(null).field");
-  self::expect(!self::isWeakMode, (#C5).{self::Class::field}, "const Class<int?>.constructor1(null).field");
+  self::expect(self::isWeakMode, (#C5).{self::Class::field}, "const Class<List<int>>.constructor1(<Null>[null]).field");
   self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor1(null).field");
   self::expect(new self::Class::constructor2<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor2(null).field");
   self::expect(true, new self::Class::constructor2<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor2(null).field");
-  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<int?>.constructor2(null).field");
+  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor2(null).field");
   self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor2(null).field");
   self::expect(new self::Class::constructor3<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<Null>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C10).{self::Class::field}, "Class<Null>.constructor3(null).field");
   self::expect(new self::Class::constructor4<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor4(null).field");
-  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<int?>.constructor4(null).field");
+  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor4(null).field");
   self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor4(null).field");
 }
 static method expect(dynamic expected, dynamic actual, core::String message) → dynamic {
@@ -85,11 +85,12 @@
   #C2 = true
   #C3 = false
   #C4 = self::Class<core::int> {field:#C3}
-  #C5 = self::Class<core::int?> {field:#C2}
+  #C5 = self::Class<core::List<core::int>> {field:#C3}
   #C6 = self::Class<Null> {field:#C2}
   #C7 = self::Class<core::int> {field:#C2}
-  #C8 = self::Class<core::int?> {field:#C3}
-  #C9 = self::Class<Null> {field:#C3}
+  #C8 = self::Class<core::int?> {field:#C2}
+  #C9 = self::Class<core::int?> {field:#C3}
+  #C10 = self::Class<Null> {field:#C3}
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd/constant_null_is.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/constant_null_is.dart.strong.transformed.expect
index 08902cf..33c269a 100644
--- a/pkg/front_end/testcases/nnbd/constant_null_is.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/constant_null_is.dart.strong.transformed.expect
@@ -34,16 +34,16 @@
 static const field core::bool c11 = #C2;
 static const field core::bool c12 = #C2;
 static const field self::Class<core::int> e1 = #C4;
-static const field self::Class<core::int?> e2 = #C5;
+static const field self::Class<core::List<core::int>> e2 = #C5;
 static const field self::Class<Null> e3 = #C6;
 static const field self::Class<core::int> e4 = #C7;
-static const field self::Class<core::int?> e5 = #C5;
+static const field self::Class<core::int?> e5 = #C8;
 static const field self::Class<Null> e6 = #C6;
 static const field self::Class<core::int> e7 = #C4;
-static const field self::Class<core::int?> e8 = #C8;
-static const field self::Class<Null> e9 = #C9;
+static const field self::Class<core::int?> e8 = #C9;
+static const field self::Class<Null> e9 = #C10;
 static const field self::Class<core::int> e10 = #C7;
-static const field self::Class<core::int?> e11 = #C5;
+static const field self::Class<core::int?> e11 = #C8;
 static const field self::Class<Null> e12 = #C6;
 static method main() → dynamic {
   self::expect(null is{ForNonNullableByDefault} core::int?, #C2, "null is int?");
@@ -61,18 +61,18 @@
   self::expect(null is{ForNonNullableByDefault} FutureOr<Never>?, #C2, "null is FutureOr<Never>?");
   self::expect(new self::Class::constructor1<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor1(null).field");
   self::expect(true, new self::Class::constructor1<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor1(null).field");
-  self::expect(!self::isWeakMode, (#C5).{self::Class::field}, "const Class<int?>.constructor1(null).field");
+  self::expect(self::isWeakMode, (#C5).{self::Class::field}, "const Class<List<int>>.constructor1(<Null>[null]).field");
   self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor1(null).field");
   self::expect(new self::Class::constructor2<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor2(null).field");
   self::expect(true, new self::Class::constructor2<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor2(null).field");
-  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<int?>.constructor2(null).field");
+  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor2(null).field");
   self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor2(null).field");
   self::expect(new self::Class::constructor3<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<Null>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C10).{self::Class::field}, "Class<Null>.constructor3(null).field");
   self::expect(new self::Class::constructor4<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor4(null).field");
-  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<int?>.constructor4(null).field");
+  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor4(null).field");
   self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor4(null).field");
 }
 static method expect(dynamic expected, dynamic actual, core::String message) → dynamic {
@@ -85,11 +85,12 @@
   #C2 = true
   #C3 = false
   #C4 = self::Class<core::int> {field:#C3}
-  #C5 = self::Class<core::int?> {field:#C2}
+  #C5 = self::Class<core::List<core::int>> {field:#C3}
   #C6 = self::Class<Null> {field:#C2}
   #C7 = self::Class<core::int> {field:#C2}
-  #C8 = self::Class<core::int?> {field:#C3}
-  #C9 = self::Class<Null> {field:#C3}
+  #C8 = self::Class<core::int?> {field:#C2}
+  #C9 = self::Class<core::int?> {field:#C3}
+  #C10 = self::Class<Null> {field:#C3}
 }
 
 Extra constant evaluation status:
@@ -107,7 +108,7 @@
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is.dart:56:15 -> BoolConstant(true)
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is.dart:57:15 -> BoolConstant(true)
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is.dart:7:40 -> BoolConstant(false)
-Extra constant evaluation: evaluated: 102, effectively constant: 14
+Extra constant evaluation: evaluated: 101, effectively constant: 14
 
 
 Constructor coverage from constants:
diff --git a/pkg/front_end/testcases/nnbd/constant_null_is.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/constant_null_is.dart.textual_outline.expect
index fcfd9f0..df16424 100644
--- a/pkg/front_end/testcases/nnbd/constant_null_is.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/nnbd/constant_null_is.dart.textual_outline.expect
@@ -15,7 +15,7 @@
 const c11 = null is FutureOr<Never?>;
 const c12 = null is FutureOr<Never>?;
 const e1 = const Class<int>.constructor1(null);
-const e2 = const Class<int?>.constructor1(null);
+const e2 = const Class<List<int>>.constructor1(<Null>[null]);
 const e3 = const Class<Null>.constructor1(null);
 const e4 = const Class<int>.constructor2(null);
 const e5 = const Class<int?>.constructor2(null);
diff --git a/pkg/front_end/testcases/nnbd/constant_null_is.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/constant_null_is.dart.textual_outline_modelled.expect
index 3c072a2..58b8052 100644
--- a/pkg/front_end/testcases/nnbd/constant_null_is.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/constant_null_is.dart.textual_outline_modelled.expect
@@ -25,7 +25,7 @@
 const e10 = const Class<int>.constructor4(null);
 const e11 = const Class<int?>.constructor4(null);
 const e12 = const Class<Null>.constructor4(null);
-const e2 = const Class<int?>.constructor1(null);
+const e2 = const Class<List<int>>.constructor1(<Null>[null]);
 const e3 = const Class<Null>.constructor1(null);
 const e4 = const Class<int>.constructor2(null);
 const e5 = const Class<int?>.constructor2(null);
diff --git a/pkg/front_end/testcases/nnbd/constant_null_is.dart.weak.expect b/pkg/front_end/testcases/nnbd/constant_null_is.dart.weak.expect
index 406d358..d9f07b7 100644
--- a/pkg/front_end/testcases/nnbd/constant_null_is.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/constant_null_is.dart.weak.expect
@@ -34,17 +34,17 @@
 static const field core::bool c11 = #C2;
 static const field core::bool c12 = #C2;
 static const field self::Class<core::int> e1 = #C4;
-static const field self::Class<core::int?> e2 = #C4;
-static const field self::Class<Null> e3 = #C5;
-static const field self::Class<core::int> e4 = #C6;
-static const field self::Class<core::int?> e5 = #C6;
-static const field self::Class<Null> e6 = #C5;
+static const field self::Class<core::List<core::int>> e2 = #C5;
+static const field self::Class<Null> e3 = #C6;
+static const field self::Class<core::int> e4 = #C7;
+static const field self::Class<core::int?> e5 = #C8;
+static const field self::Class<Null> e6 = #C6;
 static const field self::Class<core::int> e7 = #C4;
-static const field self::Class<core::int?> e8 = #C4;
-static const field self::Class<Null> e9 = #C7;
-static const field self::Class<core::int> e10 = #C6;
-static const field self::Class<core::int?> e11 = #C6;
-static const field self::Class<Null> e12 = #C5;
+static const field self::Class<core::int?> e8 = #C9;
+static const field self::Class<Null> e9 = #C10;
+static const field self::Class<core::int> e10 = #C7;
+static const field self::Class<core::int?> e11 = #C8;
+static const field self::Class<Null> e12 = #C6;
 static method main() → dynamic {
   self::expect(null is{ForNonNullableByDefault} core::int?, #C2, "null is int?");
   self::expect(null is{ForNonNullableByDefault} core::int, #C3, "null is int");
@@ -61,19 +61,19 @@
   self::expect(null is{ForNonNullableByDefault} FutureOr<Never>?, #C2, "null is FutureOr<Never>?");
   self::expect(new self::Class::constructor1<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor1(null).field");
   self::expect(true, new self::Class::constructor1<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor1(null).field");
-  self::expect(!self::isWeakMode, (#C4).{self::Class::field}, "const Class<int?>.constructor1(null).field");
-  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor1(null).field");
-  self::expect(new self::Class::constructor2<core::int>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor2(null).field");
+  self::expect(self::isWeakMode, (#C5).{self::Class::field}, "const Class<List<int>>.constructor1(<Null>[null]).field");
+  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor1(null).field");
+  self::expect(new self::Class::constructor2<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor2(null).field");
   self::expect(true, new self::Class::constructor2<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor2(null).field");
-  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int?>.constructor2(null).field");
-  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor2(null).field");
+  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor2(null).field");
+  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor2(null).field");
   self::expect(new self::Class::constructor3<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<Null>.constructor3(null).field");
-  self::expect(new self::Class::constructor4<core::int>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor4(null).field");
-  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int?>.constructor4(null).field");
-  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor4(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C10).{self::Class::field}, "Class<Null>.constructor3(null).field");
+  self::expect(new self::Class::constructor4<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor4(null).field");
+  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor4(null).field");
+  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor4(null).field");
 }
 static method expect(dynamic expected, dynamic actual, core::String message) → dynamic {
   if(!expected.{core::Object::==}(actual))
@@ -85,9 +85,12 @@
   #C2 = true
   #C3 = false
   #C4 = self::Class<core::int*> {field:#C3}
-  #C5 = self::Class<Null> {field:#C2}
-  #C6 = self::Class<core::int*> {field:#C2}
-  #C7 = self::Class<Null> {field:#C3}
+  #C5 = self::Class<core::List<core::int*>*> {field:#C2}
+  #C6 = self::Class<Null> {field:#C2}
+  #C7 = self::Class<core::int*> {field:#C2}
+  #C8 = self::Class<core::int?> {field:#C2}
+  #C9 = self::Class<core::int?> {field:#C3}
+  #C10 = self::Class<Null> {field:#C3}
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd/constant_null_is.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/constant_null_is.dart.weak.transformed.expect
index 35d0686..9710d1f 100644
--- a/pkg/front_end/testcases/nnbd/constant_null_is.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/constant_null_is.dart.weak.transformed.expect
@@ -34,17 +34,17 @@
 static const field core::bool c11 = #C2;
 static const field core::bool c12 = #C2;
 static const field self::Class<core::int> e1 = #C4;
-static const field self::Class<core::int?> e2 = #C4;
-static const field self::Class<Null> e3 = #C5;
-static const field self::Class<core::int> e4 = #C6;
-static const field self::Class<core::int?> e5 = #C6;
-static const field self::Class<Null> e6 = #C5;
+static const field self::Class<core::List<core::int>> e2 = #C5;
+static const field self::Class<Null> e3 = #C6;
+static const field self::Class<core::int> e4 = #C7;
+static const field self::Class<core::int?> e5 = #C8;
+static const field self::Class<Null> e6 = #C6;
 static const field self::Class<core::int> e7 = #C4;
-static const field self::Class<core::int?> e8 = #C4;
-static const field self::Class<Null> e9 = #C7;
-static const field self::Class<core::int> e10 = #C6;
-static const field self::Class<core::int?> e11 = #C6;
-static const field self::Class<Null> e12 = #C5;
+static const field self::Class<core::int?> e8 = #C9;
+static const field self::Class<Null> e9 = #C10;
+static const field self::Class<core::int> e10 = #C7;
+static const field self::Class<core::int?> e11 = #C8;
+static const field self::Class<Null> e12 = #C6;
 static method main() → dynamic {
   self::expect(null is{ForNonNullableByDefault} core::int?, #C2, "null is int?");
   self::expect(null is{ForNonNullableByDefault} core::int, #C3, "null is int");
@@ -61,19 +61,19 @@
   self::expect(null is{ForNonNullableByDefault} FutureOr<Never>?, #C2, "null is FutureOr<Never>?");
   self::expect(new self::Class::constructor1<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor1(null).field");
   self::expect(true, new self::Class::constructor1<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor1(null).field");
-  self::expect(!self::isWeakMode, (#C4).{self::Class::field}, "const Class<int?>.constructor1(null).field");
-  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor1(null).field");
-  self::expect(new self::Class::constructor2<core::int>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor2(null).field");
+  self::expect(self::isWeakMode, (#C5).{self::Class::field}, "const Class<List<int>>.constructor1(<Null>[null]).field");
+  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor1(null).field");
+  self::expect(new self::Class::constructor2<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor2(null).field");
   self::expect(true, new self::Class::constructor2<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor2(null).field");
-  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int?>.constructor2(null).field");
-  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor2(null).field");
+  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor2(null).field");
+  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor2(null).field");
   self::expect(new self::Class::constructor3<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<Null>.constructor3(null).field");
-  self::expect(new self::Class::constructor4<core::int>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor4(null).field");
-  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int?>.constructor4(null).field");
-  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor4(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C10).{self::Class::field}, "Class<Null>.constructor3(null).field");
+  self::expect(new self::Class::constructor4<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor4(null).field");
+  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor4(null).field");
+  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor4(null).field");
 }
 static method expect(dynamic expected, dynamic actual, core::String message) → dynamic {
   if(!expected.{core::Object::==}(actual))
@@ -85,9 +85,12 @@
   #C2 = true
   #C3 = false
   #C4 = self::Class<core::int*> {field:#C3}
-  #C5 = self::Class<Null> {field:#C2}
-  #C6 = self::Class<core::int*> {field:#C2}
-  #C7 = self::Class<Null> {field:#C3}
+  #C5 = self::Class<core::List<core::int*>*> {field:#C2}
+  #C6 = self::Class<Null> {field:#C2}
+  #C7 = self::Class<core::int*> {field:#C2}
+  #C8 = self::Class<core::int?> {field:#C2}
+  #C9 = self::Class<core::int?> {field:#C3}
+  #C10 = self::Class<Null> {field:#C3}
 }
 
 Extra constant evaluation status:
@@ -105,7 +108,7 @@
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is.dart:56:15 -> BoolConstant(true)
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is.dart:57:15 -> BoolConstant(true)
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is.dart:7:40 -> BoolConstant(true)
-Extra constant evaluation: evaluated: 102, effectively constant: 14
+Extra constant evaluation: evaluated: 101, effectively constant: 14
 
 
 Constructor coverage from constants:
diff --git a/pkg/front_end/testcases/nnbd/constants.dart.weak.expect b/pkg/front_end/testcases/nnbd/constants.dart.weak.expect
index 607aec4..759f798 100644
--- a/pkg/front_end/testcases/nnbd/constants.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/constants.dart.weak.expect
@@ -88,13 +88,13 @@
   return t;
 
 constants  {
-  #C1 = TypeLiteralConstant(core::Object)
+  #C1 = TypeLiteralConstant(core::Object*)
   #C2 = tearoff con::id
   #C3 = partial-instantiation con::id <core::int*>
   #C4 = 0
   #C5 = con::Class<core::int*> {field:#C4}
-  #C6 = TypeLiteralConstant((dynamic) → dynamic)
-  #C7 = TypeLiteralConstant(<T extends core::Object? = dynamic>(T%) → T%)
+  #C6 = TypeLiteralConstant((dynamic) →* dynamic)
+  #C7 = TypeLiteralConstant(<T extends core::Object? = dynamic>(T*) →* T*)
   #C8 = <core::int*>[#C4]
   #C9 = null
   #C10 = <dynamic>[#C4, #C9]
diff --git a/pkg/front_end/testcases/nnbd/constants.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/constants.dart.weak.transformed.expect
index 607aec4..759f798 100644
--- a/pkg/front_end/testcases/nnbd/constants.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/constants.dart.weak.transformed.expect
@@ -88,13 +88,13 @@
   return t;
 
 constants  {
-  #C1 = TypeLiteralConstant(core::Object)
+  #C1 = TypeLiteralConstant(core::Object*)
   #C2 = tearoff con::id
   #C3 = partial-instantiation con::id <core::int*>
   #C4 = 0
   #C5 = con::Class<core::int*> {field:#C4}
-  #C6 = TypeLiteralConstant((dynamic) → dynamic)
-  #C7 = TypeLiteralConstant(<T extends core::Object? = dynamic>(T%) → T%)
+  #C6 = TypeLiteralConstant((dynamic) →* dynamic)
+  #C7 = TypeLiteralConstant(<T extends core::Object? = dynamic>(T*) →* T*)
   #C8 = <core::int*>[#C4]
   #C9 = null
   #C10 = <dynamic>[#C4, #C9]
diff --git a/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.strong.expect b/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.strong.expect
index 4f5c95f..7994771 100644
--- a/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.strong.expect
@@ -57,7 +57,7 @@
   return new self::Class::•();
 }
 static method test2<T extends self::Class = self::Class>(self::test2::T t2) → dynamic {
-  if(self::test2::T.{core::Type::==}(self::SubClass)) {
+  if(self::test2::T.{core::Type::==}(#C1)) {
     self::SubClass subClass = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart:26:28: Error: A value of type 'T' can't be assigned to a variable of type 'SubClass'.
  - 'SubClass' is from 'pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart'.
     SubClass subClass = t2.method2();
@@ -74,3 +74,7 @@
   }
 }
 static method main() → dynamic {}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::SubClass)
+}
diff --git a/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.strong.transformed.expect
index c60f2f0..a0d52ef 100644
--- a/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.strong.transformed.expect
@@ -57,7 +57,7 @@
   return new self::Class::•();
 }
 static method test2<T extends self::Class = self::Class>(self::test2::T t2) → dynamic {
-  if(self::test2::T.{core::Type::==}(self::SubClass)) {
+  if(self::test2::T.{core::Type::==}(#C1)) {
     self::SubClass subClass = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart:26:28: Error: A value of type 'T' can't be assigned to a variable of type 'SubClass'.
  - 'SubClass' is from 'pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart'.
     SubClass subClass = t2.method2();
@@ -75,7 +75,6 @@
 }
 static method main() → dynamic {}
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///extension_type_variable_bound.dart:25:12 -> TypeLiteralConstant(SubClass)
-Extra constant evaluation: evaluated: 24, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(self::SubClass)
+}
diff --git a/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.weak.expect b/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.weak.expect
index 4f5c95f..bb758a4 100644
--- a/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.weak.expect
@@ -57,7 +57,7 @@
   return new self::Class::•();
 }
 static method test2<T extends self::Class = self::Class>(self::test2::T t2) → dynamic {
-  if(self::test2::T.{core::Type::==}(self::SubClass)) {
+  if(self::test2::T.{core::Type::==}(#C1)) {
     self::SubClass subClass = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart:26:28: Error: A value of type 'T' can't be assigned to a variable of type 'SubClass'.
  - 'SubClass' is from 'pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart'.
     SubClass subClass = t2.method2();
@@ -74,3 +74,7 @@
   }
 }
 static method main() → dynamic {}
+
+constants  {
+  #C1 = TypeLiteralConstant(self::SubClass*)
+}
diff --git a/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.weak.transformed.expect
index c60f2f0..f53f0bc 100644
--- a/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart.weak.transformed.expect
@@ -57,7 +57,7 @@
   return new self::Class::•();
 }
 static method test2<T extends self::Class = self::Class>(self::test2::T t2) → dynamic {
-  if(self::test2::T.{core::Type::==}(self::SubClass)) {
+  if(self::test2::T.{core::Type::==}(#C1)) {
     self::SubClass subClass = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart:26:28: Error: A value of type 'T' can't be assigned to a variable of type 'SubClass'.
  - 'SubClass' is from 'pkg/front_end/testcases/nnbd/extension_type_variable_bound.dart'.
     SubClass subClass = t2.method2();
@@ -75,7 +75,6 @@
 }
 static method main() → dynamic {}
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///extension_type_variable_bound.dart:25:12 -> TypeLiteralConstant(SubClass)
-Extra constant evaluation: evaluated: 24, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(self::SubClass*)
+}
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
index 601d9fb..ac239e8 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
@@ -1,3 +1,8 @@
+//
+// Problems outside component:
+//
+// third_party/pkg/ffi/lib/src/allocation.dart: Info: Support for using non-constant type arguments 'T' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type.
+//
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
index 601d9fb..ac239e8 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
@@ -1,3 +1,8 @@
+//
+// Problems outside component:
+//
+// third_party/pkg/ffi/lib/src/allocation.dart: Info: Support for using non-constant type arguments 'T' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type.
+//
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
diff --git a/pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart.weak.expect b/pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart.weak.expect
index f936ed5..f526302 100644
--- a/pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart.weak.expect
@@ -1,52 +1,37 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:8:12: Error: Constant evaluation error:
-// const c2 = {a: 0, b: 1};
-//            ^
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:8:19: Context: The key '<int>[]' conflicts with another existing key in the map.
-// const c2 = {a: 0, b: 1};
-//                   ^
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:8:7: Context: While analyzing:
-// const c2 = {a: 0, b: 1};
-//       ^
-//
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:9:12: Error: Constant evaluation error:
-// const c3 = {a, b};
-//            ^
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:9:16: Context: The element '<int>[]' conflicts with another existing element in the set.
-// const c3 = {a, b};
-//                ^
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:9:7: Context: While analyzing:
-// const c3 = {a, b};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 import "org-dartlang-testcase:///from_agnostic_lib.dart";
 
 static const field core::bool c1 = #C1;
-static const field core::Map<core::List<core::int?>, core::int> c2 = invalid-expression "The key '<int>[]' conflicts with another existing key in the map.";
-static const field core::Set<core::List<core::int?>> c3 = invalid-expression "The element '<int>[]' conflicts with another existing element in the set.";
+static const field core::Map<core::List<core::int?>, core::int> c2 = #C7;
+static const field core::Set<core::List<core::int?>> c3 = #C11;
 static const field core::List<core::int> c4 = #C2;
-static const field core::List<core::int?> c5 = #C2;
+static const field core::List<core::int?> c5 = #C4;
 static method main() → dynamic {
   #C2;
-  #C2;
+  #C4;
 }
 
 library /*isNonNullableByDefault*/;
 import self as self2;
 import "dart:core" as core;
 
-static const field core::List<core::int> a = #C3;
+static const field core::List<core::int> a = #C12;
 static const field core::List<core::int?> b = #C4;
 
 constants  {
-  #C1 = true
+  #C1 = false
   #C2 = <core::int*>[]
-  #C3 = <core::int>[]
+  #C3 = 0
   #C4 = <core::int?>[]
+  #C5 = 1
+  #C6 = <dynamic>[#C2, #C3, #C4, #C5]
+  #C7 = core::_ImmutableMap<core::List<core::int?>*, core::int*> {_kvPairs:#C6}
+  #C8 = null
+  #C9 = <dynamic>[#C2, #C8, #C4, #C8]
+  #C10 = core::_ImmutableMap<core::List<core::int?>*, Null> {_kvPairs:#C9}
+  #C11 = col::_UnmodifiableSet<core::List<core::int?>*> {_map:#C10}
+  #C12 = <core::int>[]
 }
diff --git a/pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart.weak.transformed.expect
index f936ed5..f526302 100644
--- a/pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart.weak.transformed.expect
@@ -1,52 +1,37 @@
 library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:8:12: Error: Constant evaluation error:
-// const c2 = {a: 0, b: 1};
-//            ^
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:8:19: Context: The key '<int>[]' conflicts with another existing key in the map.
-// const c2 = {a: 0, b: 1};
-//                   ^
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:8:7: Context: While analyzing:
-// const c2 = {a: 0, b: 1};
-//       ^
-//
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:9:12: Error: Constant evaluation error:
-// const c3 = {a, b};
-//            ^
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:9:16: Context: The element '<int>[]' conflicts with another existing element in the set.
-// const c3 = {a, b};
-//                ^
-// pkg/front_end/testcases/nnbd/from_agnostic/from_agnostic.dart:9:7: Context: While analyzing:
-// const c3 = {a, b};
-//       ^
-//
 import self as self;
 import "dart:core" as core;
 
 import "org-dartlang-testcase:///from_agnostic_lib.dart";
 
 static const field core::bool c1 = #C1;
-static const field core::Map<core::List<core::int?>, core::int> c2 = invalid-expression "The key '<int>[]' conflicts with another existing key in the map.";
-static const field core::Set<core::List<core::int?>> c3 = invalid-expression "The element '<int>[]' conflicts with another existing element in the set.";
+static const field core::Map<core::List<core::int?>, core::int> c2 = #C7;
+static const field core::Set<core::List<core::int?>> c3 = #C11;
 static const field core::List<core::int> c4 = #C2;
-static const field core::List<core::int?> c5 = #C2;
+static const field core::List<core::int?> c5 = #C4;
 static method main() → dynamic {
   #C2;
-  #C2;
+  #C4;
 }
 
 library /*isNonNullableByDefault*/;
 import self as self2;
 import "dart:core" as core;
 
-static const field core::List<core::int> a = #C3;
+static const field core::List<core::int> a = #C12;
 static const field core::List<core::int?> b = #C4;
 
 constants  {
-  #C1 = true
+  #C1 = false
   #C2 = <core::int*>[]
-  #C3 = <core::int>[]
+  #C3 = 0
   #C4 = <core::int?>[]
+  #C5 = 1
+  #C6 = <dynamic>[#C2, #C3, #C4, #C5]
+  #C7 = core::_ImmutableMap<core::List<core::int?>*, core::int*> {_kvPairs:#C6}
+  #C8 = null
+  #C9 = <dynamic>[#C2, #C8, #C4, #C8]
+  #C10 = core::_ImmutableMap<core::List<core::int?>*, Null> {_kvPairs:#C9}
+  #C11 = col::_UnmodifiableSet<core::List<core::int?>*> {_map:#C10}
+  #C12 = <core::int>[]
 }
diff --git a/pkg/front_end/testcases/nnbd/issue41273.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue41273.dart.strong.expect
index eff260bc..6eef4f6 100644
--- a/pkg/front_end/testcases/nnbd/issue41273.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/issue41273.dart.strong.expect
@@ -13,7 +13,7 @@
     Never n7 = x{Never}.call();
     Never n8 = x{Never}.runtimeType();
     Never n9 = x{Never}.toString;
-    x{Never}.runtimeType = core::Object;
+    x{Never}.runtimeType = #C1;
     x{Never}.toString = () → core::String => "";
     Never v1 = x{Never}.toString();
     Never v2 = x{Never}.runtimeType;
@@ -29,3 +29,7 @@
 static method main() → dynamic {
   self::test(null);
 }
+
+constants  {
+  #C1 = TypeLiteralConstant(core::Object)
+}
diff --git a/pkg/front_end/testcases/nnbd/issue41273.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue41273.dart.strong.transformed.expect
index 368f224..6eef4f6 100644
--- a/pkg/front_end/testcases/nnbd/issue41273.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue41273.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
     Never n7 = x{Never}.call();
     Never n8 = x{Never}.runtimeType();
     Never n9 = x{Never}.toString;
-    x{Never}.runtimeType = core::Object;
+    x{Never}.runtimeType = #C1;
     x{Never}.toString = () → core::String => "";
     Never v1 = x{Never}.toString();
     Never v2 = x{Never}.runtimeType;
@@ -30,7 +30,6 @@
   self::test(null);
 }
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///issue41273.dart:16:21 -> TypeLiteralConstant(Object)
-Extra constant evaluation: evaluated: 49, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(core::Object)
+}
diff --git a/pkg/front_end/testcases/nnbd/issue41273.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue41273.dart.weak.expect
index 8c49c0f..e220d05 100644
--- a/pkg/front_end/testcases/nnbd/issue41273.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/issue41273.dart.weak.expect
@@ -14,7 +14,7 @@
     Never n7 = let final Never #t15 = (let final Never #t16 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).call() in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
     Never n8 = let final Never #t17 = (let final Never #t18 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).runtimeType() in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
     Never n9 = let final Never #t19 = (let final Never #t20 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).toString in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
-    (let final Never #t21 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).runtimeType = core::Object;
+    (let final Never #t21 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).runtimeType = #C1;
     (let final Never #t22 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).toString = () → core::String => "";
     Never v1 = let final Never #t23 = (let final Never #t24 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).toString() in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
     Never v2 = let final Never #t25 = (let final Never #t26 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).runtimeType in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
@@ -30,3 +30,7 @@
 static method main() → dynamic {
   self::test(null);
 }
+
+constants  {
+  #C1 = TypeLiteralConstant(core::Object*)
+}
diff --git a/pkg/front_end/testcases/nnbd/issue41273.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue41273.dart.weak.transformed.expect
index e7749a6..e220d05 100644
--- a/pkg/front_end/testcases/nnbd/issue41273.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue41273.dart.weak.transformed.expect
@@ -14,7 +14,7 @@
     Never n7 = let final Never #t15 = (let final Never #t16 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).call() in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
     Never n8 = let final Never #t17 = (let final Never #t18 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).runtimeType() in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
     Never n9 = let final Never #t19 = (let final Never #t20 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).toString in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
-    (let final Never #t21 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).runtimeType = core::Object;
+    (let final Never #t21 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).runtimeType = #C1;
     (let final Never #t22 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).toString = () → core::String => "";
     Never v1 = let final Never #t23 = (let final Never #t24 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).toString() in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
     Never v2 = let final Never #t25 = (let final Never #t26 = x{Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")).runtimeType in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
@@ -31,7 +31,6 @@
   self::test(null);
 }
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///issue41273.dart:16:21 -> TypeLiteralConstant(Object)
-Extra constant evaluation: evaluated: 175, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(core::Object*)
+}
diff --git a/pkg/front_end/testcases/nnbd/issue41657.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue41657.dart.weak.expect
index 0065c49..574dddd 100644
--- a/pkg/front_end/testcases/nnbd/issue41657.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/issue41657.dart.weak.expect
@@ -20,5 +20,5 @@
 constants  {
   #C1 = true
   #C2 = <Null>[]
-  #C3 = <core::int*>[]
+  #C3 = <core::int?>[]
 }
diff --git a/pkg/front_end/testcases/nnbd/issue41657.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue41657.dart.weak.transformed.expect
index 6d6049e..c5fa19e 100644
--- a/pkg/front_end/testcases/nnbd/issue41657.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue41657.dart.weak.transformed.expect
@@ -20,5 +20,5 @@
 constants  {
   #C1 = true
   #C2 = <Null>[]
-  #C3 = <core::int*>[]
+  #C3 = <core::int?>[]
 }
diff --git a/pkg/front_end/testcases/nnbd/potentially_constant_type_as.dart.weak.expect b/pkg/front_end/testcases/nnbd/potentially_constant_type_as.dart.weak.expect
index 2f79aaf..9abe043 100644
--- a/pkg/front_end/testcases/nnbd/potentially_constant_type_as.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/potentially_constant_type_as.dart.weak.expect
@@ -237,7 +237,7 @@
   #C20 = self::ClassWithList<core::String*> {field:#C19}
   #C21 = tearoff self::dynamicFunction
   #C22 = self::ClassWithFunction<dynamic> {field:#C21}
-  #C23 = self::ClassWithFunction<core::Object*> {field:#C21}
+  #C23 = self::ClassWithFunction<core::Object?> {field:#C21}
   #C24 = tearoff self::objectFunction
   #C25 = self::ClassWithFunction<dynamic> {field:#C24}
   #C26 = self::ClassWithFunction<void> {field:#C24}
diff --git a/pkg/front_end/testcases/nnbd/potentially_constant_type_as.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/potentially_constant_type_as.dart.weak.transformed.expect
index 2f79aaf..9abe043 100644
--- a/pkg/front_end/testcases/nnbd/potentially_constant_type_as.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/potentially_constant_type_as.dart.weak.transformed.expect
@@ -237,7 +237,7 @@
   #C20 = self::ClassWithList<core::String*> {field:#C19}
   #C21 = tearoff self::dynamicFunction
   #C22 = self::ClassWithFunction<dynamic> {field:#C21}
-  #C23 = self::ClassWithFunction<core::Object*> {field:#C21}
+  #C23 = self::ClassWithFunction<core::Object?> {field:#C21}
   #C24 = tearoff self::objectFunction
   #C25 = self::ClassWithFunction<dynamic> {field:#C24}
   #C26 = self::ClassWithFunction<void> {field:#C24}
diff --git a/pkg/front_end/testcases/nnbd/potentially_constant_type_is.dart.weak.expect b/pkg/front_end/testcases/nnbd/potentially_constant_type_is.dart.weak.expect
index ca7b07c..da6412f 100644
--- a/pkg/front_end/testcases/nnbd/potentially_constant_type_is.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/potentially_constant_type_is.dart.weak.expect
@@ -58,24 +58,24 @@
   #C17;
   #C18;
   #C18;
-  #C16;
-  #C20;
+  #C19;
   #C21;
   #C22;
   #C23;
-  #C23;
-  #C23;
+  #C24;
+  #C24;
   #C24;
   #C25;
   #C26;
   #C27;
   #C28;
   #C29;
-  #C29;
+  #C30;
   #C30;
   #C31;
   #C32;
   #C33;
+  #C34;
 }
 
 constants  {
@@ -94,24 +94,25 @@
   #C13 = self::ClassWithList<core::int*> {field:#C4}
   #C14 = self::ClassWithList<core::String*> {field:#C4}
   #C15 = self::ClassWithFunction<dynamic> {field:#C4}
-  #C16 = self::ClassWithFunction<core::Object*> {field:#C4}
+  #C16 = self::ClassWithFunction<core::Object?> {field:#C4}
   #C17 = self::ClassWithFunction<void> {field:#C4}
   #C18 = self::ClassWithFunction<core::int*> {field:#C4}
-  #C19 = false
-  #C20 = self::Class<core::num*> {field:#C19}
-  #C21 = self::Class<core::int*> {field:#C19}
-  #C22 = self::Class<core::String*> {field:#C19}
-  #C23 = self::ClassWithBound<core::double*> {field:#C19}
-  #C24 = self::ClassWithBound<core::num*> {field:#C19}
-  #C25 = self::ClassWithList<dynamic> {field:#C19}
-  #C26 = self::ClassWithList<core::num*> {field:#C19}
-  #C27 = self::ClassWithList<core::int*> {field:#C19}
-  #C28 = self::ClassWithList<core::String*> {field:#C19}
-  #C29 = self::ClassWithFunction<dynamic> {field:#C19}
-  #C30 = self::ClassWithFunction<core::Object*> {field:#C19}
-  #C31 = self::ClassWithFunction<void> {field:#C19}
-  #C32 = self::ClassWithFunction<core::num*> {field:#C19}
-  #C33 = self::ClassWithFunction<core::int*> {field:#C19}
+  #C19 = self::ClassWithFunction<core::Object*> {field:#C4}
+  #C20 = false
+  #C21 = self::Class<core::num*> {field:#C20}
+  #C22 = self::Class<core::int*> {field:#C20}
+  #C23 = self::Class<core::String*> {field:#C20}
+  #C24 = self::ClassWithBound<core::double*> {field:#C20}
+  #C25 = self::ClassWithBound<core::num*> {field:#C20}
+  #C26 = self::ClassWithList<dynamic> {field:#C20}
+  #C27 = self::ClassWithList<core::num*> {field:#C20}
+  #C28 = self::ClassWithList<core::int*> {field:#C20}
+  #C29 = self::ClassWithList<core::String*> {field:#C20}
+  #C30 = self::ClassWithFunction<dynamic> {field:#C20}
+  #C31 = self::ClassWithFunction<core::Object*> {field:#C20}
+  #C32 = self::ClassWithFunction<void> {field:#C20}
+  #C33 = self::ClassWithFunction<core::num*> {field:#C20}
+  #C34 = self::ClassWithFunction<core::int*> {field:#C20}
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd/potentially_constant_type_is.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/potentially_constant_type_is.dart.weak.transformed.expect
index ca7b07c..da6412f 100644
--- a/pkg/front_end/testcases/nnbd/potentially_constant_type_is.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/potentially_constant_type_is.dart.weak.transformed.expect
@@ -58,24 +58,24 @@
   #C17;
   #C18;
   #C18;
-  #C16;
-  #C20;
+  #C19;
   #C21;
   #C22;
   #C23;
-  #C23;
-  #C23;
+  #C24;
+  #C24;
   #C24;
   #C25;
   #C26;
   #C27;
   #C28;
   #C29;
-  #C29;
+  #C30;
   #C30;
   #C31;
   #C32;
   #C33;
+  #C34;
 }
 
 constants  {
@@ -94,24 +94,25 @@
   #C13 = self::ClassWithList<core::int*> {field:#C4}
   #C14 = self::ClassWithList<core::String*> {field:#C4}
   #C15 = self::ClassWithFunction<dynamic> {field:#C4}
-  #C16 = self::ClassWithFunction<core::Object*> {field:#C4}
+  #C16 = self::ClassWithFunction<core::Object?> {field:#C4}
   #C17 = self::ClassWithFunction<void> {field:#C4}
   #C18 = self::ClassWithFunction<core::int*> {field:#C4}
-  #C19 = false
-  #C20 = self::Class<core::num*> {field:#C19}
-  #C21 = self::Class<core::int*> {field:#C19}
-  #C22 = self::Class<core::String*> {field:#C19}
-  #C23 = self::ClassWithBound<core::double*> {field:#C19}
-  #C24 = self::ClassWithBound<core::num*> {field:#C19}
-  #C25 = self::ClassWithList<dynamic> {field:#C19}
-  #C26 = self::ClassWithList<core::num*> {field:#C19}
-  #C27 = self::ClassWithList<core::int*> {field:#C19}
-  #C28 = self::ClassWithList<core::String*> {field:#C19}
-  #C29 = self::ClassWithFunction<dynamic> {field:#C19}
-  #C30 = self::ClassWithFunction<core::Object*> {field:#C19}
-  #C31 = self::ClassWithFunction<void> {field:#C19}
-  #C32 = self::ClassWithFunction<core::num*> {field:#C19}
-  #C33 = self::ClassWithFunction<core::int*> {field:#C19}
+  #C19 = self::ClassWithFunction<core::Object*> {field:#C4}
+  #C20 = false
+  #C21 = self::Class<core::num*> {field:#C20}
+  #C22 = self::Class<core::int*> {field:#C20}
+  #C23 = self::Class<core::String*> {field:#C20}
+  #C24 = self::ClassWithBound<core::double*> {field:#C20}
+  #C25 = self::ClassWithBound<core::num*> {field:#C20}
+  #C26 = self::ClassWithList<dynamic> {field:#C20}
+  #C27 = self::ClassWithList<core::num*> {field:#C20}
+  #C28 = self::ClassWithList<core::int*> {field:#C20}
+  #C29 = self::ClassWithList<core::String*> {field:#C20}
+  #C30 = self::ClassWithFunction<dynamic> {field:#C20}
+  #C31 = self::ClassWithFunction<core::Object*> {field:#C20}
+  #C32 = self::ClassWithFunction<void> {field:#C20}
+  #C33 = self::ClassWithFunction<core::num*> {field:#C20}
+  #C34 = self::ClassWithFunction<core::int*> {field:#C20}
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart
new file mode 100644
index 0000000..1a480bd
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart
@@ -0,0 +1,127 @@
+// 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.
+
+import 'dart:async';
+import './const_canonical_type_lib.dart' as oo;
+
+class Check {
+  final _ignored;
+
+  const Check(x, y)
+      : assert(identical(x, y)),
+      _ignored = identical(x, y) ? 42 : 1 ~/ 0;
+}
+
+void expectEqual(x, y) {
+  if (x != y) {
+    throw "Arguments were supposed to be identical.";
+  }
+}
+
+typedef F1 = oo.A<FutureOr<dynamic>> Function();
+typedef F2 = oo.A<dynamic> Function();
+typedef F3 = oo.A<FutureOr<FutureOr<dynamic>?>> Function();
+typedef F4 = oo.A Function();
+
+test1() {
+  const c = oo.A;
+  var v = oo.A;
+
+  expectEqual(c, v);
+  expectEqual(v, oo.c);
+  expectEqual(oo.c, oo.v);
+  expectEqual(oo.v, oo.A);
+  expectEqual(oo.A, c);
+
+  const cf1 = F1;
+  const cf2 = F2;
+  const cf3 = F3;
+  const cf4 = F4;
+  const oocf1 = oo.F1;
+  const oocf2 = oo.F2;
+  const oocf3 = oo.F3;
+  const oocf4 = oo.F4;
+  var vf1 = F1;
+  var vf2 = F2;
+  var vf3 = F3;
+  var vf4 = F4;
+  var oovf1 = oo.F1;
+  var oovf2 = oo.F2;
+  var oovf3 = oo.F3;
+  var oovf4 = oo.F4;
+
+  expectEqual(cf1, cf2);
+  expectEqual(cf2, cf3);
+  expectEqual(cf3, cf4);
+  expectEqual(cf4, oocf1);
+  expectEqual(oocf1, oocf2);
+  expectEqual(oocf2, oocf3);
+  expectEqual(oocf3, oocf4);
+  expectEqual(oocf4, vf1);
+  expectEqual(vf1, vf2);
+  expectEqual(vf2, vf3);
+  expectEqual(vf3, vf4);
+  expectEqual(vf4, oovf1);
+  expectEqual(oovf1, oovf2);
+  expectEqual(oovf2, oovf3);
+  expectEqual(oovf3, oovf4);
+  expectEqual(oovf4, F1);
+  expectEqual(F1, F2);
+  expectEqual(F2, F3);
+  expectEqual(F3, F4);
+  expectEqual(F4, oo.F1);
+  expectEqual(oo.F1, oo.F2);
+  expectEqual(oo.F2, oo.F3);
+  expectEqual(oo.F3, oo.F4);
+  expectEqual(oo.F1, cf1);
+
+  const a1 = oo.A<List<F1>>();
+  const a2 = oo.A<List<F2>>();
+  const a3 = oo.A<List<F3>>();
+  const a4 = oo.A<List<F4>>();
+
+  return const <dynamic>[
+    Check(c, c),
+    Check(c, oo.A),
+    Check(oo.A, oo.A),
+
+    Check(cf1, cf2),
+    Check(cf2, cf3),
+    Check(cf3, cf4),
+    Check(cf4, oocf1),
+    Check(oocf1, oocf2),
+    Check(oocf2, oocf3),
+    Check(oocf3, oocf4),
+    Check(oocf4, F1),
+    Check(F1, F2),
+    Check(F2, F3),
+    Check(F3, F4),
+    Check(F4, oo.F1),
+    Check(oo.F1, oo.F2),
+    Check(oo.F2, oo.F3),
+    Check(oo.F3, oo.F4),
+    Check(oo.F4, cf1),
+
+    Check(a1, a2),
+    Check(a2, a3),
+    Check(a3, a4),
+    Check(a4, oo.a1),
+    Check(oo.a1, oo.a2),
+    Check(oo.a2, oo.a3),
+    Check(oo.a3, oo.a4),
+    Check(oo.a4, const oo.A<List<F1>>()),
+    Check(const oo.A<List<F1>>(), const oo.A<List<F2>>()),
+    Check(const oo.A<List<F2>>(), const oo.A<List<F3>>()),
+    Check(const oo.A<List<F3>>(), const oo.A<List<F4>>()),
+    Check(const oo.A<List<F4>>(), const oo.A<List<oo.F1>>()),
+    Check(const oo.A<List<oo.F1>>(), const oo.A<List<oo.F2>>()),
+    Check(const oo.A<List<oo.F2>>(), const oo.A<List<oo.F3>>()),
+    Check(const oo.A<List<oo.F3>>(), const oo.A<List<oo.F4>>()),
+    Check(const oo.A<List<oo.F4>>(), a1),
+  ];
+}
+
+main() {
+  test1();
+}
diff --git a/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.textual_outline.expect
new file mode 100644
index 0000000..86981f3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.textual_outline.expect
@@ -0,0 +1,17 @@
+import 'dart:async';
+import './const_canonical_type_lib.dart' as oo;
+
+class Check {
+  final _ignored;
+  const Check(x, y)
+      : assert(identical(x, y)),
+        _ignored = identical(x, y) ? 42 : 1 ~/ 0;
+}
+
+void expectEqual(x, y) {}
+typedef F1 = oo.A<FutureOr<dynamic>> Function();
+typedef F2 = oo.A<dynamic> Function();
+typedef F3 = oo.A<FutureOr<FutureOr<dynamic>?>> Function();
+typedef F4 = oo.A Function();
+test1() {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..daaeb63
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.textual_outline_modelled.expect
@@ -0,0 +1,17 @@
+import './const_canonical_type_lib.dart' as oo;
+import 'dart:async';
+
+class Check {
+  const Check(x, y)
+      : assert(identical(x, y)),
+        _ignored = identical(x, y) ? 42 : 1 ~/ 0;
+  final _ignored;
+}
+
+main() {}
+test1() {}
+typedef F1 = oo.A<FutureOr<dynamic>> Function();
+typedef F2 = oo.A<dynamic> Function();
+typedef F3 = oo.A<FutureOr<FutureOr<dynamic>?>> Function();
+typedef F4 = oo.A Function();
+void expectEqual(x, y) {}
diff --git a/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.weak.expect
new file mode 100644
index 0000000..a49b865
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.weak.expect
@@ -0,0 +1,119 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "const_canonical_type_lib.dart" as con;
+import "dart:core" as core;
+
+import "dart:async";
+import "org-dartlang-testcase:///const_canonical_type_lib.dart" as oo;
+
+typedef F1 = () → con::A<FutureOr<dynamic>>;
+typedef F2 = () → con::A<dynamic>;
+typedef F3 = () → con::A<FutureOr<FutureOr<dynamic>?>>;
+typedef F4 = () → con::A<dynamic>;
+class Check extends core::Object /*hasConstConstructor*/  {
+  final field dynamic _ignored;
+  const constructor •(dynamic x, dynamic y) → self::Check
+    : assert(core::identical(x, y)), self::Check::_ignored = core::identical(x, y) ?{core::int} 42 : 1.{core::num::~/}(0), super core::Object::•()
+    ;
+}
+static method expectEqual(dynamic x, dynamic y) → void {
+  if(!x.{core::Object::==}(y)) {
+    throw "Arguments were supposed to be identical.";
+  }
+}
+static method test1() → dynamic {
+  core::Type v = #C1;
+  self::expectEqual(#C1, v);
+  self::expectEqual(v, #C1);
+  self::expectEqual(#C1, con::v);
+  self::expectEqual(con::v, #C1);
+  self::expectEqual(#C1, #C1);
+  core::Type vf1 = #C2;
+  core::Type vf2 = #C2;
+  core::Type vf3 = #C2;
+  core::Type vf4 = #C2;
+  core::Type oovf1 = #C2;
+  core::Type oovf2 = #C2;
+  core::Type oovf3 = #C2;
+  core::Type oovf4 = #C2;
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, vf1);
+  self::expectEqual(vf1, vf2);
+  self::expectEqual(vf2, vf3);
+  self::expectEqual(vf3, vf4);
+  self::expectEqual(vf4, oovf1);
+  self::expectEqual(oovf1, oovf2);
+  self::expectEqual(oovf2, oovf3);
+  self::expectEqual(oovf3, oovf4);
+  self::expectEqual(oovf4, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  return #C5;
+}
+static method main() → dynamic {
+  self::test1();
+}
+
+library;
+import self as con;
+import "dart:core" as core;
+
+import "dart:async";
+
+typedef F1 = () →* con::A<FutureOr<dynamic>*>*;
+typedef F2 = () →* con::A<dynamic>*;
+typedef F3 = () →* con::A<FutureOr<FutureOr<dynamic>*>*>*;
+typedef F4 = () →* con::A<dynamic>*;
+class A<X extends core::Object* = dynamic> extends core::Object /*hasConstConstructor*/  {
+  const constructor •() → con::A<con::A::X*>*
+    : super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+static const field core::Type* c = #C1;
+static field core::Type* v = #C1;
+static const field con::A<core::List<() →* con::A<FutureOr<dynamic>*>*>*>* a1 = #C6;
+static const field con::A<core::List<() →* con::A<dynamic>*>*>* a2 = #C6;
+static const field con::A<core::List<() →* con::A<FutureOr<FutureOr<dynamic>*>*>*>*>* a3 = #C6;
+static const field con::A<core::List<() →* con::A<dynamic>*>*>* a4 = #C6;
+
+constants  {
+  #C1 = TypeLiteralConstant(con::A<dynamic>*)
+  #C2 = TypeLiteralConstant(() →* con::A<dynamic>*)
+  #C3 = 42
+  #C4 = self::Check {_ignored:#C3}
+  #C5 = <dynamic>[#C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4]
+  #C6 = con::A<core::List<() →* con::A<dynamic>*>*> {}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_canonical_type.dart:
+- A. (from org-dartlang-testcase:///const_canonical_type_lib.dart:10:9)
+- Check. (from org-dartlang-testcase:///const_canonical_type.dart:11:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+
+org-dartlang-testcase:///const_canonical_type_lib.dart:
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- A. (from org-dartlang-testcase:///const_canonical_type_lib.dart:10:9)
diff --git a/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.weak.transformed.expect
new file mode 100644
index 0000000..a49b865
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type.dart.weak.transformed.expect
@@ -0,0 +1,119 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "const_canonical_type_lib.dart" as con;
+import "dart:core" as core;
+
+import "dart:async";
+import "org-dartlang-testcase:///const_canonical_type_lib.dart" as oo;
+
+typedef F1 = () → con::A<FutureOr<dynamic>>;
+typedef F2 = () → con::A<dynamic>;
+typedef F3 = () → con::A<FutureOr<FutureOr<dynamic>?>>;
+typedef F4 = () → con::A<dynamic>;
+class Check extends core::Object /*hasConstConstructor*/  {
+  final field dynamic _ignored;
+  const constructor •(dynamic x, dynamic y) → self::Check
+    : assert(core::identical(x, y)), self::Check::_ignored = core::identical(x, y) ?{core::int} 42 : 1.{core::num::~/}(0), super core::Object::•()
+    ;
+}
+static method expectEqual(dynamic x, dynamic y) → void {
+  if(!x.{core::Object::==}(y)) {
+    throw "Arguments were supposed to be identical.";
+  }
+}
+static method test1() → dynamic {
+  core::Type v = #C1;
+  self::expectEqual(#C1, v);
+  self::expectEqual(v, #C1);
+  self::expectEqual(#C1, con::v);
+  self::expectEqual(con::v, #C1);
+  self::expectEqual(#C1, #C1);
+  core::Type vf1 = #C2;
+  core::Type vf2 = #C2;
+  core::Type vf3 = #C2;
+  core::Type vf4 = #C2;
+  core::Type oovf1 = #C2;
+  core::Type oovf2 = #C2;
+  core::Type oovf3 = #C2;
+  core::Type oovf4 = #C2;
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, vf1);
+  self::expectEqual(vf1, vf2);
+  self::expectEqual(vf2, vf3);
+  self::expectEqual(vf3, vf4);
+  self::expectEqual(vf4, oovf1);
+  self::expectEqual(oovf1, oovf2);
+  self::expectEqual(oovf2, oovf3);
+  self::expectEqual(oovf3, oovf4);
+  self::expectEqual(oovf4, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  self::expectEqual(#C2, #C2);
+  return #C5;
+}
+static method main() → dynamic {
+  self::test1();
+}
+
+library;
+import self as con;
+import "dart:core" as core;
+
+import "dart:async";
+
+typedef F1 = () →* con::A<FutureOr<dynamic>*>*;
+typedef F2 = () →* con::A<dynamic>*;
+typedef F3 = () →* con::A<FutureOr<FutureOr<dynamic>*>*>*;
+typedef F4 = () →* con::A<dynamic>*;
+class A<X extends core::Object* = dynamic> extends core::Object /*hasConstConstructor*/  {
+  const constructor •() → con::A<con::A::X*>*
+    : super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+static const field core::Type* c = #C1;
+static field core::Type* v = #C1;
+static const field con::A<core::List<() →* con::A<FutureOr<dynamic>*>*>*>* a1 = #C6;
+static const field con::A<core::List<() →* con::A<dynamic>*>*>* a2 = #C6;
+static const field con::A<core::List<() →* con::A<FutureOr<FutureOr<dynamic>*>*>*>*>* a3 = #C6;
+static const field con::A<core::List<() →* con::A<dynamic>*>*>* a4 = #C6;
+
+constants  {
+  #C1 = TypeLiteralConstant(con::A<dynamic>*)
+  #C2 = TypeLiteralConstant(() →* con::A<dynamic>*)
+  #C3 = 42
+  #C4 = self::Check {_ignored:#C3}
+  #C5 = <dynamic>[#C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4, #C4]
+  #C6 = con::A<core::List<() →* con::A<dynamic>*>*> {}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_canonical_type.dart:
+- A. (from org-dartlang-testcase:///const_canonical_type_lib.dart:10:9)
+- Check. (from org-dartlang-testcase:///const_canonical_type.dart:11:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+
+org-dartlang-testcase:///const_canonical_type_lib.dart:
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- A. (from org-dartlang-testcase:///const_canonical_type_lib.dart:10:9)
diff --git a/pkg/front_end/testcases/nnbd_mixed/const_canonical_type_lib.dart b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type_lib.dart
new file mode 100644
index 0000000..4c380bd
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/const_canonical_type_lib.dart
@@ -0,0 +1,24 @@
+// 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.
+
+// @dart=2.6
+
+import 'dart:async';
+
+class A<X> {
+  const A();
+}
+
+typedef F1 = A<FutureOr<dynamic>> Function();
+typedef F2 = A<dynamic> Function();
+typedef F3 = A<FutureOr<FutureOr<dynamic>>> Function();
+typedef F4 = A Function();
+
+const c = A;
+var v = A;
+
+const a1 = A<List<F1>>();
+const a2 = A<List<F2>>();
+const a3 = A<List<F3>>();
+const a4 = A<List<F4>>();
diff --git a/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart b/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart
index b061200..a5289e6 100644
--- a/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart
+++ b/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart
@@ -21,7 +21,7 @@
 const c11 = null is FutureOr<Never?>;
 const c12 = null is FutureOr<Never>?;
 const e1 = const Class<int>.constructor1(null);
-const e2 = const Class<int?>.constructor1(null);
+const e2 = const Class<List<int>>.constructor1(<Null>[null]);
 const e3 = const Class<Null>.constructor1(null);
 const e4 = const Class<int>.constructor2(null);
 const e5 = const Class<int?>.constructor2(null);
@@ -60,15 +60,17 @@
       "Class<int>.constructor1(null).field");
   expect(true, new Class<int?>.constructor1(null).field,
       "new Class<int?>.constructor1(null).field");
-  // const Class<int?> is evaluated as const Class<int*> in weak mode:
-  expect(!isWeakMode, e2.field, "const Class<int?>.constructor1(null).field");
+  // const Class<List<int>> is evaluated as const Class<List<int*>*> in weak
+  // mode:
+  expect(isWeakMode, e2.field,
+      "const Class<List<int>>.constructor1(<Null>[null]).field");
   expect(new Class<Null>.constructor1(null).field, e3.field,
       "Class<Null>.constructor1(null).field");
   expect(new Class<int>.constructor2(null).field, e4.field,
       "Class<int>.constructor2(null).field");
   expect(true, new Class<int?>.constructor2(null).field,
       "new Class<int?>.constructor2(null).field");
-  // const Class<int?> is evaluated as const Class<int*> in weak mode:
+  // const Class<int?> is evaluated as const Class<int?> in weak mode:
   expect(new Class<int?>.constructor2(null).field, e5.field,
       "Class<int?>.constructor2(null).field");
   expect(new Class<Null>.constructor2(null).field, e6.field,
diff --git a/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.textual_outline.expect
index baf0ddd..d5d0290 100644
--- a/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.textual_outline.expect
@@ -16,7 +16,7 @@
 const c11 = null is FutureOr<Never?>;
 const c12 = null is FutureOr<Never>?;
 const e1 = const Class<int>.constructor1(null);
-const e2 = const Class<int?>.constructor1(null);
+const e2 = const Class<List<int>>.constructor1(<Null>[null]);
 const e3 = const Class<Null>.constructor1(null);
 const e4 = const Class<int>.constructor2(null);
 const e5 = const Class<int?>.constructor2(null);
diff --git a/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.textual_outline_modelled.expect
index 15ed19a8..04b1f5d 100644
--- a/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.textual_outline_modelled.expect
@@ -26,7 +26,7 @@
 const e10 = const Class<int>.constructor4(null);
 const e11 = const Class<int?>.constructor4(null);
 const e12 = const Class<Null>.constructor4(null);
-const e2 = const Class<int?>.constructor1(null);
+const e2 = const Class<List<int>>.constructor1(<Null>[null]);
 const e3 = const Class<Null>.constructor1(null);
 const e4 = const Class<int>.constructor2(null);
 const e5 = const Class<int?>.constructor2(null);
diff --git a/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.weak.expect
index 420216c..cd7b899 100644
--- a/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.weak.expect
@@ -36,17 +36,17 @@
 static const field core::bool c11 = #C2;
 static const field core::bool c12 = #C2;
 static const field self::Class<core::int> e1 = #C4;
-static const field self::Class<core::int?> e2 = #C4;
-static const field self::Class<Null> e3 = #C5;
-static const field self::Class<core::int> e4 = #C6;
-static const field self::Class<core::int?> e5 = #C6;
-static const field self::Class<Null> e6 = #C5;
+static const field self::Class<core::List<core::int>> e2 = #C5;
+static const field self::Class<Null> e3 = #C6;
+static const field self::Class<core::int> e4 = #C7;
+static const field self::Class<core::int?> e5 = #C8;
+static const field self::Class<Null> e6 = #C6;
 static const field self::Class<core::int> e7 = #C4;
-static const field self::Class<core::int?> e8 = #C4;
-static const field self::Class<Null> e9 = #C7;
-static const field self::Class<core::int> e10 = #C6;
-static const field self::Class<core::int?> e11 = #C6;
-static const field self::Class<Null> e12 = #C5;
+static const field self::Class<core::int?> e8 = #C9;
+static const field self::Class<Null> e9 = #C10;
+static const field self::Class<core::int> e10 = #C7;
+static const field self::Class<core::int?> e11 = #C8;
+static const field self::Class<Null> e12 = #C6;
 static method main() → dynamic {
   self::expect(null is{ForNonNullableByDefault} core::int?, #C2, "null is int?");
   self::expect(null is{ForNonNullableByDefault} core::int, #C3, "null is int");
@@ -63,19 +63,19 @@
   self::expect(null is{ForNonNullableByDefault} FutureOr<Never>?, #C2, "null is FutureOr<Never>?");
   self::expect(new self::Class::constructor1<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor1(null).field");
   self::expect(true, new self::Class::constructor1<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor1(null).field");
-  self::expect(!self::isWeakMode, (#C4).{self::Class::field}, "const Class<int?>.constructor1(null).field");
-  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor1(null).field");
-  self::expect(new self::Class::constructor2<core::int>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor2(null).field");
+  self::expect(self::isWeakMode, (#C5).{self::Class::field}, "const Class<List<int>>.constructor1(<Null>[null]).field");
+  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor1(null).field");
+  self::expect(new self::Class::constructor2<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor2(null).field");
   self::expect(true, new self::Class::constructor2<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor2(null).field");
-  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int?>.constructor2(null).field");
-  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor2(null).field");
+  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor2(null).field");
+  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor2(null).field");
   self::expect(new self::Class::constructor3<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<Null>.constructor3(null).field");
-  self::expect(new self::Class::constructor4<core::int>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor4(null).field");
-  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int?>.constructor4(null).field");
-  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor4(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C10).{self::Class::field}, "Class<Null>.constructor3(null).field");
+  self::expect(new self::Class::constructor4<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor4(null).field");
+  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor4(null).field");
+  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor4(null).field");
   con::test();
 }
 static method expect(dynamic expected, dynamic actual, core::String message) → dynamic {
@@ -94,24 +94,24 @@
 static const field core::bool* d0 = #C3;
 static const field core::bool* d1 = #C2;
 static const field self::Class<core::int*>* d4 = #C4;
-static const field self::Class<Null>* d5 = #C5;
-static const field self::Class<core::int*>* d6 = #C6;
-static const field self::Class<Null>* d7 = #C5;
+static const field self::Class<Null>* d5 = #C6;
+static const field self::Class<core::int*>* d6 = #C7;
+static const field self::Class<Null>* d7 = #C6;
 static const field self::Class<core::int*>* d8 = #C4;
-static const field self::Class<Null>* d9 = #C7;
-static const field self::Class<core::int*>* d10 = #C6;
-static const field self::Class<Null>* d11 = #C5;
+static const field self::Class<Null>* d9 = #C10;
+static const field self::Class<core::int*>* d10 = #C7;
+static const field self::Class<Null>* d11 = #C6;
 static method test() → dynamic {
   self::expect(null is core::int*, #C3, "null is int (opt-out)");
   self::expect(null is Null, #C2, "null is Null");
   self::expect(new self::Class::constructor1<core::int*>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor1(null).field (opt-out)");
-  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor1(null).field (opt-out)");
-  self::expect(new self::Class::constructor2<core::int*>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor2(null).field (opt-out)");
-  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor2(null).field (opt-out)");
+  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor1(null).field (opt-out)");
+  self::expect(new self::Class::constructor2<core::int*>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor2(null).field (opt-out)");
+  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor2(null).field (opt-out)");
   self::expect(new self::Class::constructor3<core::int*>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor3(null).field (opt-out)");
-  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<Null>.constructor3(null).field (opt-out)");
-  self::expect(new self::Class::constructor4<core::int*>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor4(null).field (opt-out)");
-  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor4(null).field (opt-out)");
+  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C10).{self::Class::field}, "Class<Null>.constructor3(null).field (opt-out)");
+  self::expect(new self::Class::constructor4<core::int*>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor4(null).field (opt-out)");
+  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor4(null).field (opt-out)");
 }
 
 constants  {
@@ -119,9 +119,12 @@
   #C2 = true
   #C3 = false
   #C4 = self::Class<core::int*> {field:#C3}
-  #C5 = self::Class<Null> {field:#C2}
-  #C6 = self::Class<core::int*> {field:#C2}
-  #C7 = self::Class<Null> {field:#C3}
+  #C5 = self::Class<core::List<core::int*>*> {field:#C2}
+  #C6 = self::Class<Null> {field:#C2}
+  #C7 = self::Class<core::int*> {field:#C2}
+  #C8 = self::Class<core::int?> {field:#C2}
+  #C9 = self::Class<core::int?> {field:#C3}
+  #C10 = self::Class<Null> {field:#C3}
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.weak.transformed.expect
index 8761b15..edf4aad 100644
--- a/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/constant_null_is.dart.weak.transformed.expect
@@ -36,17 +36,17 @@
 static const field core::bool c11 = #C2;
 static const field core::bool c12 = #C2;
 static const field self::Class<core::int> e1 = #C4;
-static const field self::Class<core::int?> e2 = #C4;
-static const field self::Class<Null> e3 = #C5;
-static const field self::Class<core::int> e4 = #C6;
-static const field self::Class<core::int?> e5 = #C6;
-static const field self::Class<Null> e6 = #C5;
+static const field self::Class<core::List<core::int>> e2 = #C5;
+static const field self::Class<Null> e3 = #C6;
+static const field self::Class<core::int> e4 = #C7;
+static const field self::Class<core::int?> e5 = #C8;
+static const field self::Class<Null> e6 = #C6;
 static const field self::Class<core::int> e7 = #C4;
-static const field self::Class<core::int?> e8 = #C4;
-static const field self::Class<Null> e9 = #C7;
-static const field self::Class<core::int> e10 = #C6;
-static const field self::Class<core::int?> e11 = #C6;
-static const field self::Class<Null> e12 = #C5;
+static const field self::Class<core::int?> e8 = #C9;
+static const field self::Class<Null> e9 = #C10;
+static const field self::Class<core::int> e10 = #C7;
+static const field self::Class<core::int?> e11 = #C8;
+static const field self::Class<Null> e12 = #C6;
 static method main() → dynamic {
   self::expect(null is{ForNonNullableByDefault} core::int?, #C2, "null is int?");
   self::expect(null is{ForNonNullableByDefault} core::int, #C3, "null is int");
@@ -63,19 +63,19 @@
   self::expect(null is{ForNonNullableByDefault} FutureOr<Never>?, #C2, "null is FutureOr<Never>?");
   self::expect(new self::Class::constructor1<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor1(null).field");
   self::expect(true, new self::Class::constructor1<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor1(null).field");
-  self::expect(!self::isWeakMode, (#C4).{self::Class::field}, "const Class<int?>.constructor1(null).field");
-  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor1(null).field");
-  self::expect(new self::Class::constructor2<core::int>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor2(null).field");
+  self::expect(self::isWeakMode, (#C5).{self::Class::field}, "const Class<List<int>>.constructor1(<Null>[null]).field");
+  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor1(null).field");
+  self::expect(new self::Class::constructor2<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor2(null).field");
   self::expect(true, new self::Class::constructor2<core::int?>(null).{self::Class::field}, "new Class<int?>.constructor2(null).field");
-  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int?>.constructor2(null).field");
-  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor2(null).field");
+  self::expect(new self::Class::constructor2<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor2(null).field");
+  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor2(null).field");
   self::expect(new self::Class::constructor3<core::int>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int?>.constructor3(null).field");
-  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<Null>.constructor3(null).field");
-  self::expect(new self::Class::constructor4<core::int>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor4(null).field");
-  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int?>.constructor4(null).field");
-  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor4(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<core::int?>(null).{self::Class::field}, (#C9).{self::Class::field}, "Class<int?>.constructor3(null).field");
+  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C10).{self::Class::field}, "Class<Null>.constructor3(null).field");
+  self::expect(new self::Class::constructor4<core::int>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor4(null).field");
+  self::expect(new self::Class::constructor4<core::int?>(null).{self::Class::field}, (#C8).{self::Class::field}, "Class<int?>.constructor4(null).field");
+  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor4(null).field");
   con::test();
 }
 static method expect(dynamic expected, dynamic actual, core::String message) → dynamic {
@@ -94,24 +94,24 @@
 static const field core::bool* d0 = #C3;
 static const field core::bool* d1 = #C2;
 static const field self::Class<core::int*>* d4 = #C4;
-static const field self::Class<Null>* d5 = #C5;
-static const field self::Class<core::int*>* d6 = #C6;
-static const field self::Class<Null>* d7 = #C5;
+static const field self::Class<Null>* d5 = #C6;
+static const field self::Class<core::int*>* d6 = #C7;
+static const field self::Class<Null>* d7 = #C6;
 static const field self::Class<core::int*>* d8 = #C4;
-static const field self::Class<Null>* d9 = #C7;
-static const field self::Class<core::int*>* d10 = #C6;
-static const field self::Class<Null>* d11 = #C5;
+static const field self::Class<Null>* d9 = #C10;
+static const field self::Class<core::int*>* d10 = #C7;
+static const field self::Class<Null>* d11 = #C6;
 static method test() → dynamic {
   self::expect(null is core::int*, #C3, "null is int (opt-out)");
   self::expect(null is Null, #C2, "null is Null");
   self::expect(new self::Class::constructor1<core::int*>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor1(null).field (opt-out)");
-  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor1(null).field (opt-out)");
-  self::expect(new self::Class::constructor2<core::int*>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor2(null).field (opt-out)");
-  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor2(null).field (opt-out)");
+  self::expect(new self::Class::constructor1<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor1(null).field (opt-out)");
+  self::expect(new self::Class::constructor2<core::int*>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor2(null).field (opt-out)");
+  self::expect(new self::Class::constructor2<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor2(null).field (opt-out)");
   self::expect(new self::Class::constructor3<core::int*>(null).{self::Class::field}, (#C4).{self::Class::field}, "Class<int>.constructor3(null).field (opt-out)");
-  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<Null>.constructor3(null).field (opt-out)");
-  self::expect(new self::Class::constructor4<core::int*>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<int>.constructor4(null).field (opt-out)");
-  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C5).{self::Class::field}, "Class<Null>.constructor4(null).field (opt-out)");
+  self::expect(new self::Class::constructor3<Null>(null).{self::Class::field}, (#C10).{self::Class::field}, "Class<Null>.constructor3(null).field (opt-out)");
+  self::expect(new self::Class::constructor4<core::int*>(null).{self::Class::field}, (#C7).{self::Class::field}, "Class<int>.constructor4(null).field (opt-out)");
+  self::expect(new self::Class::constructor4<Null>(null).{self::Class::field}, (#C6).{self::Class::field}, "Class<Null>.constructor4(null).field (opt-out)");
 }
 
 constants  {
@@ -119,9 +119,12 @@
   #C2 = true
   #C3 = false
   #C4 = self::Class<core::int*> {field:#C3}
-  #C5 = self::Class<Null> {field:#C2}
-  #C6 = self::Class<core::int*> {field:#C2}
-  #C7 = self::Class<Null> {field:#C3}
+  #C5 = self::Class<core::List<core::int*>*> {field:#C2}
+  #C6 = self::Class<Null> {field:#C2}
+  #C7 = self::Class<core::int*> {field:#C2}
+  #C8 = self::Class<core::int?> {field:#C2}
+  #C9 = self::Class<core::int?> {field:#C3}
+  #C10 = self::Class<Null> {field:#C3}
 }
 
 Extra constant evaluation status:
@@ -141,7 +144,7 @@
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is.dart:8:40 -> BoolConstant(true)
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is_lib.dart:24:15 -> BoolConstant(false)
 Evaluated: IsExpression @ org-dartlang-testcase:///constant_null_is_lib.dart:25:15 -> BoolConstant(true)
-Extra constant evaluation: evaluated: 139, effectively constant: 16
+Extra constant evaluation: evaluated: 138, effectively constant: 16
 
 
 Constructor coverage from constants:
diff --git a/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_in.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_in.dart.weak.expect
index a706f8a..5055729 100644
--- a/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_in.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_in.dart.weak.expect
@@ -115,7 +115,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class LegacyClass4c extends core::Object implements inh::GenericInterface<core::num?> {
+class LegacyClass4c extends core::Object implements inh::GenericInterface<core::num*> {
   synthetic constructor •() → self::LegacyClass4c*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/nnbd_mixed/issue41657.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/issue41657.dart.weak.expect
index 6654a73..c0a3ef7 100644
--- a/pkg/front_end/testcases/nnbd_mixed/issue41657.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/issue41657.dart.weak.expect
@@ -24,5 +24,5 @@
 constants  {
   #C1 = <Null>[]
   #C2 = true
-  #C3 = <core::int*>[]
+  #C3 = <core::int?>[]
 }
diff --git a/pkg/front_end/testcases/nnbd_mixed/issue41657.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/issue41657.dart.weak.transformed.expect
index 9a8aafd..49fce36 100644
--- a/pkg/front_end/testcases/nnbd_mixed/issue41657.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/issue41657.dart.weak.transformed.expect
@@ -24,7 +24,7 @@
 constants  {
   #C1 = <Null>[]
   #C2 = true
-  #C3 = <core::int*>[]
+  #C3 = <core::int?>[]
 }
 
 Extra constant evaluation status:
diff --git a/pkg/front_end/testcases/nnbd_mixed/literal_from_opt_in.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/literal_from_opt_in.dart.weak.expect
index 113b863..6c3539d 100644
--- a/pkg/front_end/testcases/nnbd_mixed/literal_from_opt_in.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/literal_from_opt_in.dart.weak.expect
@@ -7,10 +7,10 @@
 
 static method main() → dynamic {
   core::List<lit::Const<core::int*>*>* l1 = #C3;
-  core::List<lit::Const<core::int*>*>* l2 = #C3;
-  core::List<lit::Const<core::int*>*>* l3 = #C6;
+  core::List<lit::Const<core::int*>*>* l2 = #C5;
+  core::List<lit::Const<core::int*>*>* l3 = #C8;
   core::List<lit::Const<core::int*>*>* l4 = #C3;
-  core::List<lit::Const<core::int*>*>* l5 = #C7;
+  core::List<lit::Const<core::int*>*>* l5 = #C9;
 }
 
 library /*isNonNullableByDefault*/;
@@ -24,19 +24,21 @@
     ;
 }
 static const field lit::Const<core::int> a = #C2;
-static const field lit::Const<core::int?> b = #C2;
-static const field lit::Const<core::int?> c = #C5;
+static const field lit::Const<core::int?> b = #C4;
+static const field lit::Const<core::int?> c = #C7;
 static const field lit::Const<core::int>? d = #C2;
-static const field lit::Const<core::int>? e = #C4;
+static const field lit::Const<core::int>? e = #C6;
 
 constants  {
   #C1 = 0
   #C2 = lit::Const<core::int*> {field:#C1}
   #C3 = <lit::Const<core::int*>*>[#C2]
-  #C4 = null
-  #C5 = lit::Const<core::int*> {field:#C4}
-  #C6 = <lit::Const<core::int*>*>[#C5]
-  #C7 = <lit::Const<core::int*>*>[#C4]
+  #C4 = lit::Const<core::int?> {field:#C1}
+  #C5 = <lit::Const<core::int*>*>[#C4]
+  #C6 = null
+  #C7 = lit::Const<core::int?> {field:#C6}
+  #C8 = <lit::Const<core::int*>*>[#C7]
+  #C9 = <lit::Const<core::int*>*>[#C6]
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd_mixed/literal_from_opt_in.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/literal_from_opt_in.dart.weak.transformed.expect
index 113b863..6c3539d 100644
--- a/pkg/front_end/testcases/nnbd_mixed/literal_from_opt_in.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/literal_from_opt_in.dart.weak.transformed.expect
@@ -7,10 +7,10 @@
 
 static method main() → dynamic {
   core::List<lit::Const<core::int*>*>* l1 = #C3;
-  core::List<lit::Const<core::int*>*>* l2 = #C3;
-  core::List<lit::Const<core::int*>*>* l3 = #C6;
+  core::List<lit::Const<core::int*>*>* l2 = #C5;
+  core::List<lit::Const<core::int*>*>* l3 = #C8;
   core::List<lit::Const<core::int*>*>* l4 = #C3;
-  core::List<lit::Const<core::int*>*>* l5 = #C7;
+  core::List<lit::Const<core::int*>*>* l5 = #C9;
 }
 
 library /*isNonNullableByDefault*/;
@@ -24,19 +24,21 @@
     ;
 }
 static const field lit::Const<core::int> a = #C2;
-static const field lit::Const<core::int?> b = #C2;
-static const field lit::Const<core::int?> c = #C5;
+static const field lit::Const<core::int?> b = #C4;
+static const field lit::Const<core::int?> c = #C7;
 static const field lit::Const<core::int>? d = #C2;
-static const field lit::Const<core::int>? e = #C4;
+static const field lit::Const<core::int>? e = #C6;
 
 constants  {
   #C1 = 0
   #C2 = lit::Const<core::int*> {field:#C1}
   #C3 = <lit::Const<core::int*>*>[#C2]
-  #C4 = null
-  #C5 = lit::Const<core::int*> {field:#C4}
-  #C6 = <lit::Const<core::int*>*>[#C5]
-  #C7 = <lit::Const<core::int*>*>[#C4]
+  #C4 = lit::Const<core::int?> {field:#C1}
+  #C5 = <lit::Const<core::int*>*>[#C4]
+  #C6 = null
+  #C7 = lit::Const<core::int?> {field:#C6}
+  #C8 = <lit::Const<core::int*>*>[#C7]
+  #C9 = <lit::Const<core::int*>*>[#C6]
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd_mixed/never_opt_out.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/never_opt_out.dart.weak.expect
index ee003ce..2572b51 100644
--- a/pkg/front_end/testcases/nnbd_mixed/never_opt_out.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/never_opt_out.dart.weak.expect
@@ -48,19 +48,19 @@
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
 class C extends nev::A {
-  field Null neverField = null;
-  field Null nullField = null;
+  field Never* neverField = null;
+  field Never* nullField = null;
   synthetic constructor •() → self::C*
     : super nev::A::•()
     ;
-  method neverMethod(Null value) → Null
+  method neverMethod(Null value) → Never*
     return value;
-  get neverProperty() → Null
+  get neverProperty() → Never*
     return null;
   set neverProperty(Null value) → void {}
-  method nullMethod(Null value) → Null
+  method nullMethod(Null value) → Never*
     return value;
-  get nullProperty() → Null
+  get nullProperty() → Never*
     return null;
   set nullProperty(Null value) → void {}
   abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
@@ -74,15 +74,15 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-static field Null optOutNever;
+static field Never* optOutNever;
 static field dynamic inferredOptOutNever = nev::optInNever;
 static method genericMethod<T extends core::Object* = dynamic>() → dynamic {}
 static method main() → dynamic {
   nev::optInNever = self::optOutNever;
-  core::Type* typeNever = Null;
-  self::genericMethod<Null>();
-  new self::GenericClass::•<Null>();
-  Null localNever = null;
+  core::Type* typeNever = #C1;
+  self::genericMethod<Never*>();
+  new self::GenericClass::•<Never*>();
+  Never* localNever = null;
   Null localNull = null;
   dynamic inferredLocalNever = nev::optInNever;
   localNever = localNever;
@@ -109,14 +109,14 @@
   localNull = localNull;
   self::inferredOptOutNever = localNull;
   inferredLocalNever = localNull;
-  localNever = self::inferredOptOutNever as{TypeError,ForDynamic} Null;
-  self::optOutNever = self::inferredOptOutNever as{TypeError,ForDynamic} Null;
+  localNever = self::inferredOptOutNever as{TypeError,ForDynamic} Never*;
+  self::optOutNever = self::inferredOptOutNever as{TypeError,ForDynamic} Never*;
   nev::optInNever = self::inferredOptOutNever as{TypeError,ForDynamic} Never;
   localNull = self::inferredOptOutNever as{TypeError,ForDynamic} Null;
   self::inferredOptOutNever = self::inferredOptOutNever;
   inferredLocalNever = self::inferredOptOutNever;
-  localNever = inferredLocalNever as{TypeError,ForDynamic} Null;
-  self::optOutNever = inferredLocalNever as{TypeError,ForDynamic} Null;
+  localNever = inferredLocalNever as{TypeError,ForDynamic} Never*;
+  self::optOutNever = inferredLocalNever as{TypeError,ForDynamic} Never*;
   nev::optInNever = inferredLocalNever as{TypeError,ForDynamic} Never;
   localNull = inferredLocalNever as{TypeError,ForDynamic} Null;
   self::inferredOptOutNever = inferredLocalNever;
@@ -181,3 +181,7 @@
   return throw "Should never return";
 static method boundedGenericMethod2<T extends Never = Never>() → core::List<nev::boundedGenericMethod2::T>
   return <nev::boundedGenericMethod2::T>[];
+
+constants  {
+  #C1 = TypeLiteralConstant(Never*)
+}
diff --git a/pkg/front_end/testcases/nnbd_mixed/never_opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/never_opt_out.dart.weak.transformed.expect
index 3c36b77..ce6f78a 100644
--- a/pkg/front_end/testcases/nnbd_mixed/never_opt_out.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/never_opt_out.dart.weak.transformed.expect
@@ -48,19 +48,19 @@
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
 class C extends nev::A {
-  field Null neverField = null;
-  field Null nullField = null;
+  field Never* neverField = null;
+  field Never* nullField = null;
   synthetic constructor •() → self::C*
     : super nev::A::•()
     ;
-  method neverMethod(Null value) → Null
+  method neverMethod(Null value) → Never*
     return value;
-  get neverProperty() → Null
+  get neverProperty() → Never*
     return null;
   set neverProperty(Null value) → void {}
-  method nullMethod(Null value) → Null
+  method nullMethod(Null value) → Never*
     return value;
-  get nullProperty() → Null
+  get nullProperty() → Never*
     return null;
   set nullProperty(Null value) → void {}
   abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
@@ -74,15 +74,15 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-static field Null optOutNever;
+static field Never* optOutNever;
 static field dynamic inferredOptOutNever = nev::optInNever;
 static method genericMethod<T extends core::Object* = dynamic>() → dynamic {}
 static method main() → dynamic {
   nev::optInNever = self::optOutNever;
-  core::Type* typeNever = Null;
-  self::genericMethod<Null>();
-  new self::GenericClass::•<Null>();
-  Null localNever = null;
+  core::Type* typeNever = #C1;
+  self::genericMethod<Never*>();
+  new self::GenericClass::•<Never*>();
+  Never* localNever = null;
   Null localNull = null;
   dynamic inferredLocalNever = nev::optInNever;
   localNever = localNever;
@@ -109,14 +109,14 @@
   localNull = localNull;
   self::inferredOptOutNever = localNull;
   inferredLocalNever = localNull;
-  localNever = self::inferredOptOutNever as{TypeError,ForDynamic} Null;
-  self::optOutNever = self::inferredOptOutNever as{TypeError,ForDynamic} Null;
+  localNever = self::inferredOptOutNever as{TypeError,ForDynamic} Never*;
+  self::optOutNever = self::inferredOptOutNever as{TypeError,ForDynamic} Never*;
   nev::optInNever = self::inferredOptOutNever as{TypeError,ForDynamic} Never;
   localNull = self::inferredOptOutNever as{TypeError,ForDynamic} Null;
   self::inferredOptOutNever = self::inferredOptOutNever;
   inferredLocalNever = self::inferredOptOutNever;
-  localNever = inferredLocalNever as{TypeError,ForDynamic} Null;
-  self::optOutNever = inferredLocalNever as{TypeError,ForDynamic} Null;
+  localNever = inferredLocalNever as{TypeError,ForDynamic} Never*;
+  self::optOutNever = inferredLocalNever as{TypeError,ForDynamic} Never*;
   nev::optInNever = inferredLocalNever as{TypeError,ForDynamic} Never;
   localNull = inferredLocalNever as{TypeError,ForDynamic} Null;
   self::inferredOptOutNever = inferredLocalNever;
@@ -182,7 +182,6 @@
 static method boundedGenericMethod2<T extends Never = Never>() → core::List<nev::boundedGenericMethod2::T>
   return core::_GrowableList::•<nev::boundedGenericMethod2::T>(0);
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///never_opt_out.dart:19:20 -> TypeLiteralConstant(Null)
-Extra constant evaluation: evaluated: 136, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(Never*)
+}
diff --git a/pkg/front_end/testcases/nnbd_mixed/object_bound_factory/main.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/object_bound_factory/main.dart.weak.expect
index 0068d5e..964ecb3 100644
--- a/pkg/front_end/testcases/nnbd_mixed/object_bound_factory/main.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/object_bound_factory/main.dart.weak.expect
@@ -96,7 +96,7 @@
 static method testOptIn() → dynamic {
   new opt::Class1::_<core::Object?>();
   new opt::Class1::_<core::Object?>();
-  #C1;
+  #C6;
   opt::Class1::fact<core::Object?>();
   new opt::Class2::_<core::Object>();
   new opt::Class2::_<core::Object>();
@@ -122,6 +122,7 @@
   #C3 = opt::Class3<core::String*> {}
   #C4 = opt::Class4<dynamic> {}
   #C5 = opt::Class5<dynamic> {}
+  #C6 = opt::Class1<core::Object?> {}
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd_mixed/object_bound_factory/main.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/object_bound_factory/main.dart.weak.transformed.expect
index 7bad5d6..46322ee 100644
--- a/pkg/front_end/testcases/nnbd_mixed/object_bound_factory/main.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/object_bound_factory/main.dart.weak.transformed.expect
@@ -96,7 +96,7 @@
 static method testOptIn() → dynamic {
   new opt::Class1::_<core::Object?>();
   new opt::Class1::_<core::Object?>();
-  #C1;
+  #C6;
   opt::Class1::fact<core::Object?>();
   new opt::Class2::_<core::Object>();
   new opt::Class2::_<core::Object>();
@@ -122,6 +122,7 @@
   #C3 = opt::Class3<core::String*> {}
   #C4 = opt::Class4<dynamic> {}
   #C5 = opt::Class5<dynamic> {}
+  #C6 = opt::Class1<core::Object?> {}
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd_mixed/opt_out.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/opt_out.dart.weak.expect
index 3869af1..afc1e53 100644
--- a/pkg/front_end/testcases/nnbd_mixed/opt_out.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/opt_out.dart.weak.expect
@@ -153,7 +153,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class B extends self2::A<core::String?> {
+class B extends self2::A<core::String*> {
   synthetic constructor •() → self2::B*
     : super self2::A::•()
     ;
@@ -162,7 +162,7 @@
 static field core::String? s = null;
 static field core::String* t = self2::s!;
 static field core::int* field = 42;
-static method method(() →? void f, {core::int* a = #C1}) → void {}
+static method method(() →* void f, {core::int* a = #C1}) → void {}
 static method errors() → dynamic {
   core::int* local = 42;
   core::List<core::String?>* l = null;
diff --git a/pkg/front_end/testcases/nnbd_mixed/opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/opt_out.dart.weak.transformed.expect
index d4d8eca..1df514c 100644
--- a/pkg/front_end/testcases/nnbd_mixed/opt_out.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/opt_out.dart.weak.transformed.expect
@@ -153,7 +153,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
-class B extends self2::A<core::String?> {
+class B extends self2::A<core::String*> {
   synthetic constructor •() → self2::B*
     : super self2::A::•()
     ;
@@ -162,7 +162,7 @@
 static field core::String? s = null;
 static field core::String* t = self2::s!;
 static field core::int* field = 42;
-static method method(() →? void f, {core::int* a = #C1}) → void {}
+static method method(() →* void f, {core::int* a = #C1}) → void {}
 static method errors() → dynamic {
   core::int* local = 42;
   core::List<core::String?>* l = null;
diff --git a/pkg/front_end/testcases/rasta/issue_000043.dart.strong.expect b/pkg/front_end/testcases/rasta/issue_000043.dart.strong.expect
index 62fa768..dd43e98 100644
--- a/pkg/front_end/testcases/rasta/issue_000043.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/issue_000043.dart.strong.expect
@@ -7,7 +7,7 @@
     : super core::Object::•()
     ;
   get x() → dynamic
-    return "${self::C*}".{core::String::hashCode};
+    return "${#C1}".{core::String::hashCode};
   abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
   abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
   abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
@@ -19,3 +19,7 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
+
+constants  {
+  #C1 = TypeLiteralConstant(self::C*)
+}
diff --git a/pkg/front_end/testcases/rasta/issue_000043.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/issue_000043.dart.strong.transformed.expect
index 9a23794..dd43e98 100644
--- a/pkg/front_end/testcases/rasta/issue_000043.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/issue_000043.dart.strong.transformed.expect
@@ -7,7 +7,7 @@
     : super core::Object::•()
     ;
   get x() → dynamic
-    return "${self::C*}".{core::String::hashCode};
+    return "${#C1}".{core::String::hashCode};
   abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
   abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
   abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
@@ -20,7 +20,6 @@
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///issue_000043.dart:6:14 -> TypeLiteralConstant(C*)
-Extra constant evaluation: evaluated: 3, effectively constant: 1
+constants  {
+  #C1 = TypeLiteralConstant(self::C*)
+}
diff --git a/pkg/front_end/testcases/rasta/type_literals.dart.strong.expect b/pkg/front_end/testcases/rasta/type_literals.dart.strong.expect
index 46122d2..d9cda9f 100644
--- a/pkg/front_end/testcases/rasta/type_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/type_literals.dart.strong.expect
@@ -291,14 +291,14 @@
     : super core::Object::•()
     ;
   method test() → dynamic {
-    self::C<dynamic>*;
-    self::use(self::C<dynamic>*);
-    dynamic;
-    self::use(dynamic);
+    #C1;
+    self::use(#C1);
+    #C2;
+    self::use(#C2);
     self::C::T*;
     self::use(self::C::T*);
-    () →* void;
-    self::use(() →* void);
+    #C3;
+    self::use(#C3);
     new self::C::•<dynamic>();
     self::use(new self::C::•<dynamic>());
     invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:22:5: Error: Method not found: 'dynamic'.
@@ -439,16 +439,16 @@
     self::use(invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:72:11: Error: Can't assign to a type literal.
     use(--Func);
           ^^^^");
-    self::C<dynamic>*.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:74:5: Error: Can't assign to a type literal.
+    (#C1).{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:74:5: Error: Can't assign to a type literal.
     C ??= 42;
     ^" : null;
-    self::use(let final core::Type* #t1 = self::C<dynamic>* in #t1.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:75:9: Error: Can't assign to a type literal.
+    self::use(let final core::Type* #t1 = #C1 in #t1.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:75:9: Error: Can't assign to a type literal.
     use(C ??= 42);
         ^" : #t1);
-    dynamic.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:76:5: Error: Can't assign to a type literal.
+    (#C2).{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:76:5: Error: Can't assign to a type literal.
     dynamic ??= 42;
     ^^^^^^^" : null;
-    self::use(let final core::Type* #t2 = dynamic in #t2.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:77:9: Error: Can't assign to a type literal.
+    self::use(let final core::Type* #t2 = #C2 in #t2.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:77:9: Error: Can't assign to a type literal.
     use(dynamic ??= 42);
         ^^^^^^^" : #t2);
     self::C::T*.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:78:5: Error: Can't assign to a type literal.
@@ -457,10 +457,10 @@
     self::use(let final core::Type* #t3 = self::C::T* in #t3.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:79:9: Error: Can't assign to a type literal.
     use(T ??= 42);
         ^" : #t3);
-    () →* void.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:80:5: Error: Can't assign to a type literal.
+    (#C3).{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:80:5: Error: Can't assign to a type literal.
     Func ??= 42;
     ^^^^" : null;
-    self::use(let final core::Type* #t4 = () →* void in #t4.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:81:9: Error: Can't assign to a type literal.
+    self::use(let final core::Type* #t4 = #C3 in #t4.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:81:9: Error: Can't assign to a type literal.
     use(Func ??= 42);
         ^^^^" : #t4);
     invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:83:5: Error: Can't assign to a type literal.
@@ -530,3 +530,9 @@
 static method main() → dynamic {
   new self::C::•<dynamic>().{self::C::test}();
 }
+
+constants  {
+  #C1 = TypeLiteralConstant(self::C<dynamic>*)
+  #C2 = TypeLiteralConstant(dynamic)
+  #C3 = TypeLiteralConstant(() →* void)
+}
diff --git a/pkg/front_end/testcases/rasta/type_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/type_literals.dart.strong.transformed.expect
index 31ed6a4..dfb5a65 100644
--- a/pkg/front_end/testcases/rasta/type_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/type_literals.dart.strong.transformed.expect
@@ -291,14 +291,14 @@
     : super core::Object::•()
     ;
   method test() → dynamic {
-    self::C<dynamic>*;
-    self::use(self::C<dynamic>*);
-    dynamic;
-    self::use(dynamic);
+    #C1;
+    self::use(#C1);
+    #C2;
+    self::use(#C2);
     self::C::T*;
     self::use(self::C::T*);
-    () →* void;
-    self::use(() →* void);
+    #C3;
+    self::use(#C3);
     new self::C::•<dynamic>();
     self::use(new self::C::•<dynamic>());
     invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:22:5: Error: Method not found: 'dynamic'.
@@ -439,16 +439,16 @@
     self::use(invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:72:11: Error: Can't assign to a type literal.
     use(--Func);
           ^^^^");
-    self::C<dynamic>*.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:74:5: Error: Can't assign to a type literal.
+    (#C1).{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:74:5: Error: Can't assign to a type literal.
     C ??= 42;
     ^" : null;
-    self::use(let final core::Type* #t1 = self::C<dynamic>* in #t1.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:75:9: Error: Can't assign to a type literal.
+    self::use(let final core::Type* #t1 = #C1 in #t1.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:75:9: Error: Can't assign to a type literal.
     use(C ??= 42);
         ^" : #t1);
-    dynamic.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:76:5: Error: Can't assign to a type literal.
+    (#C2).{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:76:5: Error: Can't assign to a type literal.
     dynamic ??= 42;
     ^^^^^^^" : null;
-    self::use(let final core::Type* #t2 = dynamic in #t2.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:77:9: Error: Can't assign to a type literal.
+    self::use(let final core::Type* #t2 = #C2 in #t2.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:77:9: Error: Can't assign to a type literal.
     use(dynamic ??= 42);
         ^^^^^^^" : #t2);
     self::C::T*.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:78:5: Error: Can't assign to a type literal.
@@ -457,10 +457,10 @@
     self::use(let final core::Type* #t3 = self::C::T* in #t3.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:79:9: Error: Can't assign to a type literal.
     use(T ??= 42);
         ^" : #t3);
-    () →* void.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:80:5: Error: Can't assign to a type literal.
+    (#C3).{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:80:5: Error: Can't assign to a type literal.
     Func ??= 42;
     ^^^^" : null;
-    self::use(let final core::Type* #t4 = () →* void in #t4.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:81:9: Error: Can't assign to a type literal.
+    self::use(let final core::Type* #t4 = #C3 in #t4.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:81:9: Error: Can't assign to a type literal.
     use(Func ??= 42);
         ^^^^" : #t4);
     invalid-expression "pkg/front_end/testcases/rasta/type_literals.dart:83:5: Error: Can't assign to a type literal.
@@ -531,18 +531,17 @@
   new self::C::•<dynamic>().{self::C::test}();
 }
 
+constants  {
+  #C1 = TypeLiteralConstant(self::C<dynamic>*)
+  #C2 = TypeLiteralConstant(dynamic)
+  #C3 = TypeLiteralConstant(() →* void)
+}
 
 Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///type_literals.dart:11:5 -> TypeLiteralConstant(C<dynamic>*)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///type_literals.dart:12:9 -> TypeLiteralConstant(C<dynamic>*)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///type_literals.dart:13:5 -> TypeLiteralConstant(dynamic)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///type_literals.dart:14:9 -> TypeLiteralConstant(dynamic)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///type_literals.dart:17:5 -> TypeLiteralConstant(void Function()*)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///type_literals.dart:18:9 -> TypeLiteralConstant(void Function()*)
 Evaluated: ConditionalExpression @ org-dartlang-testcase:///type_literals.dart:74:7 -> NullConstant(null)
 Evaluated: Let @ org-dartlang-testcase:///type_literals.dart:75:11 -> TypeLiteralConstant(C<dynamic>*)
 Evaluated: ConditionalExpression @ org-dartlang-testcase:///type_literals.dart:76:13 -> NullConstant(null)
 Evaluated: Let @ org-dartlang-testcase:///type_literals.dart:77:17 -> TypeLiteralConstant(dynamic)
 Evaluated: ConditionalExpression @ org-dartlang-testcase:///type_literals.dart:80:10 -> NullConstant(null)
 Evaluated: Let @ org-dartlang-testcase:///type_literals.dart:81:14 -> TypeLiteralConstant(void Function()*)
-Extra constant evaluation: evaluated: 72, effectively constant: 12
+Extra constant evaluation: evaluated: 66, effectively constant: 6
diff --git a/pkg/front_end/testcases/rasta/typedef.dart.strong.expect b/pkg/front_end/testcases/rasta/typedef.dart.strong.expect
index 777322c..e46b1bf 100644
--- a/pkg/front_end/testcases/rasta/typedef.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/typedef.dart.strong.expect
@@ -19,14 +19,18 @@
 
 typedef Foo = () →* void;
 static method main() → dynamic {
-  core::print(() →* void);
+  core::print(#C1);
   invalid-expression "pkg/front_end/testcases/rasta/typedef.dart:9:3: Error: Can't assign to a type literal.
   Foo = null;
   ^^^";
-  () →* void.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/typedef.dart:10:3: Error: Can't assign to a type literal.
+  (#C1).{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/typedef.dart:10:3: Error: Can't assign to a type literal.
   Foo ??= null;
   ^^^" : null;
   invalid-expression "pkg/front_end/testcases/rasta/typedef.dart:11:3: Error: Method not found: 'Foo'.
   Foo();
   ^^^";
 }
+
+constants  {
+  #C1 = TypeLiteralConstant(() →* void)
+}
diff --git a/pkg/front_end/testcases/rasta/typedef.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/typedef.dart.strong.transformed.expect
index 625cf29..611a358 100644
--- a/pkg/front_end/testcases/rasta/typedef.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/typedef.dart.strong.transformed.expect
@@ -19,11 +19,11 @@
 
 typedef Foo = () →* void;
 static method main() → dynamic {
-  core::print(() →* void);
+  core::print(#C1);
   invalid-expression "pkg/front_end/testcases/rasta/typedef.dart:9:3: Error: Can't assign to a type literal.
   Foo = null;
   ^^^";
-  () →* void.{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/typedef.dart:10:3: Error: Can't assign to a type literal.
+  (#C1).{core::Type::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/rasta/typedef.dart:10:3: Error: Can't assign to a type literal.
   Foo ??= null;
   ^^^" : null;
   invalid-expression "pkg/front_end/testcases/rasta/typedef.dart:11:3: Error: Method not found: 'Foo'.
@@ -31,8 +31,10 @@
   ^^^";
 }
 
+constants  {
+  #C1 = TypeLiteralConstant(() →* void)
+}
 
 Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///typedef.dart:8:9 -> TypeLiteralConstant(void Function()*)
 Evaluated: ConditionalExpression @ org-dartlang-testcase:///typedef.dart:10:7 -> NullConstant(null)
-Extra constant evaluation: evaluated: 3, effectively constant: 2
+Extra constant evaluation: evaluated: 2, effectively constant: 1
diff --git a/pkg/front_end/testcases/rasta/unresolved_for_in.dart.strong.expect b/pkg/front_end/testcases/rasta/unresolved_for_in.dart.strong.expect
index 8a74c31..eda1e6f 100644
--- a/pkg/front_end/testcases/rasta/unresolved_for_in.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/unresolved_for_in.dart.strong.expect
@@ -109,7 +109,7 @@
       invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:14:10: Error: Can't assign to a type literal.
     for (Fisk in x) {
          ^^^^";
-      core::print(self::Fisk*);
+      core::print(#C1);
     }
     for (final dynamic #t3 in x as{TypeError,ForDynamic} core::Iterable<dynamic>*) {
       invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:17:10: Error: A prefix can't be used as an expression.
@@ -123,7 +123,7 @@
       invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:20:10: Error: Can't assign to a type literal.
     for (VoidFunction in x) {
          ^^^^^^^^^^^^";
-      core::print(() →* void);
+      core::print(#C2);
     }
     {
       invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:23:10: Error: Can't assign to this, so it can't be used in a for-in loop.
@@ -167,7 +167,7 @@
     invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:34:8: Error: Can't assign to a type literal.
   for (Fisk in arguments) {
        ^^^^";
-    core::print(self::Fisk*);
+    core::print(#C1);
   }
   for (final dynamic #t8 in arguments as{TypeError,ForDynamic} core::Iterable<dynamic>*) {
     invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:37:8: Error: A prefix can't be used as an expression.
@@ -181,7 +181,7 @@
     invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:40:8: Error: Can't assign to a type literal.
   for (VoidFunction in arguments) {
        ^^^^^^^^^^^^";
-    core::print(() →* void);
+    core::print(#C2);
   }
   {
     invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:43:8: Error: Can't assign to this, so it can't be used in a for-in loop.
@@ -198,3 +198,8 @@
     }
   }
 }
+
+constants  {
+  #C1 = TypeLiteralConstant(self::Fisk*)
+  #C2 = TypeLiteralConstant(() →* void)
+}
diff --git a/pkg/front_end/testcases/rasta/unresolved_for_in.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/unresolved_for_in.dart.strong.transformed.expect
index 85061fb..c8cfe5a 100644
--- a/pkg/front_end/testcases/rasta/unresolved_for_in.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/unresolved_for_in.dart.strong.transformed.expect
@@ -119,7 +119,7 @@
           invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:14:10: Error: Can't assign to a type literal.
     for (Fisk in x) {
          ^^^^";
-          core::print(self::Fisk*);
+          core::print(#C1);
         }
       }
     }
@@ -145,7 +145,7 @@
           invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:20:10: Error: Can't assign to a type literal.
     for (VoidFunction in x) {
          ^^^^^^^^^^^^";
-          core::print(() →* void);
+          core::print(#C2);
         }
       }
     }
@@ -207,7 +207,7 @@
         invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:34:8: Error: Can't assign to a type literal.
   for (Fisk in arguments) {
        ^^^^";
-        core::print(self::Fisk*);
+        core::print(#C1);
       }
     }
   }
@@ -233,7 +233,7 @@
         invalid-expression "pkg/front_end/testcases/rasta/unresolved_for_in.dart:40:8: Error: Can't assign to a type literal.
   for (VoidFunction in arguments) {
        ^^^^^^^^^^^^";
-        core::print(() →* void);
+        core::print(#C2);
       }
     }
   }
@@ -259,10 +259,7 @@
   }
 }
 
-
-Extra constant evaluation status:
-Evaluated: TypeLiteral @ org-dartlang-testcase:///unresolved_for_in.dart:15:13 -> TypeLiteralConstant(Fisk*)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///unresolved_for_in.dart:21:13 -> TypeLiteralConstant(void Function()*)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///unresolved_for_in.dart:35:11 -> TypeLiteralConstant(Fisk*)
-Evaluated: TypeLiteral @ org-dartlang-testcase:///unresolved_for_in.dart:41:11 -> TypeLiteralConstant(void Function()*)
-Extra constant evaluation: evaluated: 85, effectively constant: 4
+constants  {
+  #C1 = TypeLiteralConstant(self::Fisk*)
+  #C2 = TypeLiteralConstant(() →* void)
+}
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index d6e635b..088d0fd 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -163,6 +163,15 @@
 /// of the algorithm for details.
 List<DartType> calculateBounds(List<TypeParameter> typeParameters,
     Class objectClass, Library contextLibrary) {
+  return calculateBoundsInternal(typeParameters, objectClass,
+      isNonNullableByDefault: contextLibrary.isNonNullableByDefault);
+}
+
+List<DartType> calculateBoundsInternal(
+    List<TypeParameter> typeParameters, Class objectClass,
+    {bool isNonNullableByDefault}) {
+  assert(isNonNullableByDefault != null);
+
   List<DartType> bounds =
       new List<DartType>.filled(typeParameters.length, null);
   for (int i = 0; i < typeParameters.length; i++) {
@@ -182,7 +191,7 @@
   TypeVariableGraph graph = new TypeVariableGraph(typeParameters, bounds);
   List<List<int>> stronglyConnected = computeStrongComponents(graph);
   final DartType topType = const DynamicType();
-  final DartType bottomType = contextLibrary.isNonNullableByDefault
+  final DartType bottomType = isNonNullableByDefault
       ? const NeverType(Nullability.nonNullable)
       : const BottomType();
   for (List<int> component in stronglyConnected) {
diff --git a/pkg/kernel/lib/src/const_canonical_type.dart b/pkg/kernel/lib/src/const_canonical_type.dart
new file mode 100644
index 0000000..202e731
--- /dev/null
+++ b/pkg/kernel/lib/src/const_canonical_type.dart
@@ -0,0 +1,216 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+// @dart = 2.9
+
+import 'package:kernel/src/bounds_checks.dart';
+
+import '../ast.dart' hide MapEntry;
+import '../core_types.dart';
+import '../type_algebra.dart';
+
+/// Computes CONST_CANONICAL_TYPE
+///
+/// The algorithm is specified at
+/// https://github.com/dart-lang/language/blob/master/accepted/future-releases/nnbd/feature-specification.md#constant-instances
+DartType computeConstCanonicalType(DartType type, CoreTypes coreTypes,
+    {bool isNonNullableByDefault}) {
+  assert(isNonNullableByDefault != null);
+
+  if (type is InvalidType) {
+    return type;
+  }
+
+  // CONST_CANONICAL_TYPE(T) = T if T is dynamic, void, Null
+  if (type is DynamicType || type is VoidType || type is NullType) {
+    return type;
+  }
+
+  // CONST_CANONICAL_TYPE(T) = T* if T is Never or Object
+  if (type is NeverType &&
+      type.declaredNullability == Nullability.nonNullable) {
+    return const NeverType(Nullability.legacy);
+  }
+  if (type == coreTypes.objectNonNullableRawType) {
+    return coreTypes.objectLegacyRawType;
+  }
+
+  // CONST_CANONICAL_TYPE(FutureOr<T>) = FutureOr<S>*
+  // where S is CONST_CANONICAL_TYPE(T)
+  if (type is FutureOrType &&
+      isTypeWithoutNullabilityMarker(type,
+          isNonNullableByDefault: isNonNullableByDefault)) {
+    return new FutureOrType(
+        computeConstCanonicalType(type.typeArgument, coreTypes,
+            isNonNullableByDefault: isNonNullableByDefault),
+        Nullability.legacy);
+  }
+
+  // CONST_CANONICAL_TYPE(T?) =
+  // let S be CONST_CANONICAL_TYPE(T)
+  // if S is R* then R?
+  // else S?
+  if (isNullableTypeConstructorApplication(type)) {
+    return computeConstCanonicalType(
+            computeTypeWithoutNullabilityMarker(type,
+                isNonNullableByDefault: isNonNullableByDefault),
+            coreTypes,
+            isNonNullableByDefault: isNonNullableByDefault)
+        .withDeclaredNullability(Nullability.nullable);
+  }
+
+  // CONST_CANONICAL_TYPE(T*) = CONST_CANONICAL_TYPE(T)
+  if (isLegacyTypeConstructorApplication(type,
+      isNonNullableByDefault: isNonNullableByDefault)) {
+    return computeConstCanonicalType(
+        computeTypeWithoutNullabilityMarker(type,
+            isNonNullableByDefault: isNonNullableByDefault),
+        coreTypes,
+        isNonNullableByDefault: isNonNullableByDefault);
+  }
+
+  // CONST_CANONICAL_TYPE(X extends T) = X*
+  if (type is TypeParameterType && type.promotedBound == null) {
+    return type.withDeclaredNullability(Nullability.legacy);
+  }
+
+  // CONST_CANONICAL_TYPE(X & T) =
+  // This case should not occur, since intersection types are not permitted as
+  // generic arguments.
+  assert(!(type is TypeParameterType && type.promotedBound != null),
+      "Intersection types are not permitted as generic arguments: '${type}'.");
+
+  // CONST_CANONICAL_TYPE(C<T0, ..., Tn>) = C<R0, ..., Rn>*
+  // where Ri is CONST_CANONICAL_TYPE(Ti)
+  // Note this includes the case of an interface type with no generic parameters
+  // (e.g int).
+  if (type is InterfaceType) {
+    assert(type.declaredNullability == Nullability.nonNullable);
+    List<DartType> typeArguments;
+    if (type.typeArguments.isEmpty) {
+      typeArguments = const <DartType>[];
+    } else {
+      typeArguments =
+          new List<DartType>.of(type.typeArguments, growable: false);
+      for (int i = 0; i < typeArguments.length; ++i) {
+        typeArguments[i] = computeConstCanonicalType(
+            typeArguments[i], coreTypes,
+            isNonNullableByDefault: isNonNullableByDefault);
+      }
+    }
+    return new InterfaceType(type.classNode, Nullability.legacy, typeArguments);
+  }
+
+  // CONST_CANONICAL_TYPE(R Function<X extends B>(S)) = F*
+  // where F = R1 Function<X extends B1>(S1)
+  // and R1 = CONST_CANONICAL_TYPE(R)
+  // and B1 = CONST_CANONICAL_TYPE(B)
+  // and S1 = CONST_CANONICAL_TYPE(S)
+  // Note, this generalizes to arbitrary number of type and term parameters.
+  if (type is FunctionType) {
+    assert(type.declaredNullability == Nullability.nonNullable);
+
+    List<TypeParameter> canonicalizedTypeParameters;
+    Map<TypeParameter, DartType> substitutionMap;
+    if (type.typeParameters.isEmpty) {
+      canonicalizedTypeParameters = const <TypeParameter>[];
+      substitutionMap = const <TypeParameter, DartType>{};
+    } else {
+      substitutionMap = <TypeParameter, DartType>{};
+      canonicalizedTypeParameters =
+          new List<TypeParameter>.of(type.typeParameters, growable: false);
+      for (TypeParameter parameter in canonicalizedTypeParameters) {
+        parameter.bound = computeConstCanonicalType(parameter.bound, coreTypes,
+            isNonNullableByDefault: isNonNullableByDefault);
+      }
+      List<DartType> defaultTypes = calculateBoundsInternal(
+          canonicalizedTypeParameters, coreTypes.objectClass,
+          isNonNullableByDefault: isNonNullableByDefault);
+      for (int i = 0; i < canonicalizedTypeParameters.length; ++i) {
+        canonicalizedTypeParameters[i].defaultType = defaultTypes[i];
+      }
+      for (int i = 0; i < canonicalizedTypeParameters.length; ++i) {
+        substitutionMap[canonicalizedTypeParameters[i]] =
+            new TypeParameterType.forAlphaRenaming(
+                type.typeParameters[i], canonicalizedTypeParameters[i]);
+      }
+    }
+
+    List<DartType> canonicalizedPositionalParameters;
+    if (type.positionalParameters.isEmpty) {
+      canonicalizedPositionalParameters = const <DartType>[];
+    } else {
+      canonicalizedPositionalParameters =
+          new List<DartType>.of(type.positionalParameters, growable: false);
+      for (int i = 0; i < canonicalizedPositionalParameters.length; ++i) {
+        DartType canonicalized = computeConstCanonicalType(
+            canonicalizedPositionalParameters[i], coreTypes,
+            isNonNullableByDefault: isNonNullableByDefault);
+        if (substitutionMap.isNotEmpty) {
+          canonicalized = substitute(canonicalized, substitutionMap);
+        }
+        canonicalizedPositionalParameters[i] = canonicalized;
+      }
+    }
+
+    List<NamedType> canonicalizedNamedParameters;
+    if (type.namedParameters.isEmpty) {
+      canonicalizedNamedParameters = const <NamedType>[];
+    } else {
+      canonicalizedNamedParameters =
+          new List<NamedType>.of(type.namedParameters, growable: false);
+      for (int i = 0; i < canonicalizedNamedParameters.length; ++i) {
+        DartType canonicalized = computeConstCanonicalType(
+            canonicalizedNamedParameters[i].type, coreTypes,
+            isNonNullableByDefault: isNonNullableByDefault);
+        if (substitutionMap.isNotEmpty) {
+          canonicalized = substitute(canonicalized, substitutionMap);
+        }
+        canonicalizedNamedParameters[i] = new NamedType(
+            canonicalizedNamedParameters[i].name, canonicalized,
+            isRequired: canonicalizedNamedParameters[i].isRequired);
+      }
+    }
+
+    DartType canonicalizedReturnType = computeConstCanonicalType(
+        type.returnType, coreTypes,
+        isNonNullableByDefault: isNonNullableByDefault);
+    if (substitutionMap.isNotEmpty) {
+      canonicalizedReturnType =
+          substitute(canonicalizedReturnType, substitutionMap);
+    }
+
+    // Canonicalize typedef type, just in case.
+    TypedefType canonicalizedTypedefType;
+    if (type.typedefType == null) {
+      canonicalizedTypedefType = null;
+    } else {
+      List<DartType> canonicalizedTypeArguments;
+      if (type.typedefType.typeArguments.isEmpty) {
+        canonicalizedTypeArguments = const <DartType>[];
+      } else {
+        canonicalizedTypeArguments = new List<DartType>.of(
+            type.typedefType.typeArguments,
+            growable: false);
+        for (int i = 0; i < canonicalizedTypeArguments.length; ++i) {
+          canonicalizedTypeArguments[i] = computeConstCanonicalType(
+              canonicalizedTypeArguments[i], coreTypes,
+              isNonNullableByDefault: isNonNullableByDefault);
+        }
+      }
+      canonicalizedTypedefType = new TypedefType(type.typedefType.typedefNode,
+          Nullability.legacy, canonicalizedTypeArguments);
+    }
+
+    return new FunctionType(canonicalizedPositionalParameters,
+        canonicalizedReturnType, Nullability.legacy,
+        namedParameters: canonicalizedNamedParameters,
+        typeParameters: canonicalizedTypeParameters,
+        requiredParameterCount: type.requiredParameterCount,
+        typedefType: canonicalizedTypedefType);
+  }
+
+  throw new StateError(
+      "Unhandled '${type.runtimeType}' in 'computeConstCanonicalType'.");
+}
diff --git a/pkg/kernel/lib/src/standard_bounds.dart b/pkg/kernel/lib/src/standard_bounds.dart
index de99a5e..086e491 100644
--- a/pkg/kernel/lib/src/standard_bounds.dart
+++ b/pkg/kernel/lib/src/standard_bounds.dart
@@ -399,9 +399,11 @@
     // [intersectNullabilities] to compute the resulting type if the subtype
     // relation is established.
     DartType typeWithoutNullabilityMarker1 =
-        computeTypeWithoutNullabilityMarker(type1, clientLibrary);
+        computeTypeWithoutNullabilityMarker(type1,
+            isNonNullableByDefault: clientLibrary.isNonNullableByDefault);
     DartType typeWithoutNullabilityMarker2 =
-        computeTypeWithoutNullabilityMarker(type2, clientLibrary);
+        computeTypeWithoutNullabilityMarker(type2,
+            isNonNullableByDefault: clientLibrary.isNonNullableByDefault);
     if (isSubtypeOf(typeWithoutNullabilityMarker1,
         typeWithoutNullabilityMarker2, SubtypeCheckMode.withNullabilities)) {
       return type1.withDeclaredNullability(intersectNullabilities(
@@ -771,9 +773,11 @@
     // uses [uniteNullabilities] to compute the resulting type if the subtype
     // relation is established.
     InterfaceType typeWithoutNullabilityMarker1 =
-        computeTypeWithoutNullabilityMarker(type1, clientLibrary);
+        computeTypeWithoutNullabilityMarker(type1,
+            isNonNullableByDefault: clientLibrary.isNonNullableByDefault);
     InterfaceType typeWithoutNullabilityMarker2 =
-        computeTypeWithoutNullabilityMarker(type2, clientLibrary);
+        computeTypeWithoutNullabilityMarker(type2,
+            isNonNullableByDefault: clientLibrary.isNonNullableByDefault);
 
     if (isSubtypeOf(typeWithoutNullabilityMarker1,
         typeWithoutNullabilityMarker2, SubtypeCheckMode.withNullabilities)) {
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index b8c60a0..93b9795 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -96,6 +96,14 @@
   return new _FreeFunctionTypeVariableVisitor().visit(type);
 }
 
+/// Returns `true` if [type] contains any free type variables
+///
+/// Returns `true` if [type] contains a [TypeParameterType] that doesn't refer
+/// to an enclosing generic [FunctionType] within [type].
+bool containsFreeTypeVariables(DartType type) {
+  return new _FreeTypeVariableVisitor().visit(type);
+}
+
 /// Generates a fresh copy of the given type parameters, with their bounds
 /// substituted to reference the new parameters.
 ///
@@ -752,6 +760,62 @@
   }
 }
 
+class _FreeTypeVariableVisitor implements DartTypeVisitor<bool> {
+  final Set<TypeParameter> variables = new Set<TypeParameter>();
+
+  _FreeTypeVariableVisitor();
+
+  bool visit(DartType node) => node.accept(this);
+
+  bool defaultDartType(DartType node) {
+    throw new UnsupportedError("Unsupported type $node (${node.runtimeType}.");
+  }
+
+  bool visitNamedType(NamedType node) {
+    return visit(node.type);
+  }
+
+  bool visitBottomType(BottomType node) => false;
+  bool visitNeverType(NeverType node) => false;
+  bool visitNullType(NullType node) => false;
+  bool visitInvalidType(InvalidType node) => false;
+  bool visitDynamicType(DynamicType node) => false;
+  bool visitVoidType(VoidType node) => false;
+
+  bool visitInterfaceType(InterfaceType node) {
+    return node.typeArguments.any(visit);
+  }
+
+  bool visitFutureOrType(FutureOrType node) {
+    return visit(node.typeArgument);
+  }
+
+  bool visitTypedefType(TypedefType node) {
+    return node.typeArguments.any(visit);
+  }
+
+  bool visitFunctionType(FunctionType node) {
+    variables.addAll(node.typeParameters);
+    bool result = node.typeParameters.any(handleTypeParameter) ||
+        node.positionalParameters.any(visit) ||
+        node.namedParameters.any(visitNamedType) ||
+        visit(node.returnType);
+    variables.removeAll(node.typeParameters);
+    return result;
+  }
+
+  bool visitTypeParameterType(TypeParameterType node) {
+    return !variables.contains(node.parameter);
+  }
+
+  bool handleTypeParameter(TypeParameter node) {
+    assert(variables.contains(node));
+    if (node.bound.accept(this)) return true;
+    if (node.defaultType == null) return false;
+    return node.defaultType.accept(this);
+  }
+}
+
 Nullability uniteNullabilities(Nullability a, Nullability b) {
   if (a == Nullability.nullable || b == Nullability.nullable) {
     return Nullability.nullable;
@@ -1023,14 +1087,18 @@
 /// returning the non-nullable version of type int.  In case of
 /// [TypeParameterType]s, the result may be either [Nullability.nonNullable] or
 /// [Nullability.undetermined], depending on the bound.
-DartType computeTypeWithoutNullabilityMarker(
-    DartType type, Library clientLibrary) {
+DartType computeTypeWithoutNullabilityMarker(DartType type,
+    {bool isNonNullableByDefault}) {
+  assert(isNonNullableByDefault != null);
+
   if (type is TypeParameterType) {
     if (type.promotedBound == null) {
       // The default nullability for library is used when there are no
       // nullability markers on the type.
-      return new TypeParameterType.withDefaultNullabilityForLibrary(
-          type.parameter, clientLibrary);
+      return new TypeParameterType(
+          type.parameter,
+          _defaultNullabilityForTypeParameterType(type.parameter,
+              isNonNullableByDefault: isNonNullableByDefault));
     } else {
       // Intersection types can't be arguments to the nullable and the legacy
       // type constructors, so nothing can be peeled off.
@@ -1051,15 +1119,92 @@
 /// type parameter.  Some examples of types declared without nullability markers
 /// are T% and S, where T and S are type parameters such that T extends Object?
 /// and S extends Object.
-bool isTypeParameterTypeWithoutNullabilityMarker(
-    TypeParameterType type, Library clientLibrary) {
+bool isTypeParameterTypeWithoutNullabilityMarker(TypeParameterType type,
+    {bool isNonNullableByDefault}) {
+  assert(isNonNullableByDefault != null);
+
   // The default nullability for library is used when there are no nullability
   // markers on the type.
   return type.promotedBound == null &&
       type.declaredNullability ==
-          new TypeParameterType.withDefaultNullabilityForLibrary(
-                  type.parameter, clientLibrary)
-              .declaredNullability;
+          _defaultNullabilityForTypeParameterType(type.parameter,
+              isNonNullableByDefault: isNonNullableByDefault);
+}
+
+bool isTypeWithoutNullabilityMarker(DartType type,
+    {bool isNonNullableByDefault}) {
+  assert(isNonNullableByDefault != null);
+  return !type.accept(new _NullabilityMarkerDetector(isNonNullableByDefault));
+}
+
+class _NullabilityMarkerDetector implements DartTypeVisitor<bool> {
+  final bool isNonNullableByDefault;
+
+  const _NullabilityMarkerDetector(this.isNonNullableByDefault);
+
+  @override
+  bool defaultDartType(DartType node) {
+    throw new UnsupportedError("Unsupported operation: "
+        "_NullabilityMarkerDetector(${node.runtimeType})");
+  }
+
+  @override
+  bool visitBottomType(BottomType node) => false;
+
+  @override
+  bool visitDynamicType(DynamicType node) => false;
+
+  @override
+  bool visitFunctionType(FunctionType node) {
+    assert(node.declaredNullability != Nullability.undetermined);
+    return node.declaredNullability == Nullability.nullable ||
+        node.declaredNullability == Nullability.legacy;
+  }
+
+  @override
+  bool visitFutureOrType(FutureOrType node) {
+    if (node.declaredNullability == Nullability.nullable ||
+        node.declaredNullability == Nullability.legacy) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  bool visitInterfaceType(InterfaceType node) {
+    assert(node.declaredNullability != Nullability.undetermined);
+    return node.declaredNullability == Nullability.nullable ||
+        node.declaredNullability == Nullability.legacy;
+  }
+
+  @override
+  bool visitInvalidType(InvalidType node) => false;
+
+  @override
+  bool visitNeverType(NeverType node) {
+    assert(node.declaredNullability != Nullability.undetermined);
+    return node.declaredNullability == Nullability.nullable ||
+        node.declaredNullability == Nullability.legacy;
+  }
+
+  @override
+  bool visitNullType(NullType node) => false;
+
+  @override
+  bool visitTypeParameterType(TypeParameterType node) {
+    return !isTypeParameterTypeWithoutNullabilityMarker(node,
+        isNonNullableByDefault: isNonNullableByDefault);
+  }
+
+  @override
+  bool visitTypedefType(TypedefType node) {
+    assert(node.declaredNullability != Nullability.undetermined);
+    return node.declaredNullability == Nullability.nullable ||
+        node.declaredNullability == Nullability.legacy;
+  }
+
+  @override
+  bool visitVoidType(VoidType node) => false;
 }
 
 /// Returns true if [type] is an application of the nullable type constructor.
@@ -1085,23 +1230,28 @@
 /// A type is considered an application of the legacy type constructor if it was
 /// declared within a legacy library and is not one of exempt types, such as
 /// dynamic or void.
-bool isLegacyTypeConstructorApplication(DartType type, Library clientLibrary) {
+bool isLegacyTypeConstructorApplication(DartType type,
+    {bool isNonNullableByDefault}) {
+  assert(isNonNullableByDefault != null);
+
   if (type is TypeParameterType) {
-    if (type.promotedBound == null) {
-      // The legacy nullability is considered an application of the legacy
-      // nullability constructor if it doesn't match the default nullability
-      // of the type-parameter type for the library.
-      return type.declaredNullability == Nullability.legacy &&
-          type.declaredNullability !=
-              new TypeParameterType.withDefaultNullabilityForLibrary(
-                      type.parameter, clientLibrary)
-                  .declaredNullability;
-    } else {
-      return false;
-    }
+    // The legacy nullability is considered an application of the legacy
+    // nullability constructor if it doesn't match the default nullability
+    // of the type-parameter type for the library.
+    return type.declaredNullability == Nullability.legacy &&
+        !isTypeParameterTypeWithoutNullabilityMarker(type,
+            isNonNullableByDefault: isNonNullableByDefault);
   } else if (type is InvalidType) {
     return false;
   } else {
     return type.declaredNullability == Nullability.legacy;
   }
 }
+
+Nullability _defaultNullabilityForTypeParameterType(TypeParameter parameter,
+    {bool isNonNullableByDefault}) {
+  assert(isNonNullableByDefault != null);
+  return isNonNullableByDefault
+      ? TypeParameterType.computeNullabilityFromBound(parameter)
+      : Nullability.legacy;
+}
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index 17ad5f5..e27e3f3 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -219,8 +219,11 @@
   final Procedure offsetByMethod;
   final Procedure elementAtMethod;
   final Procedure addressGetter;
+  final Procedure structPointerRef;
+  final Procedure structPointerElemAt;
   final Procedure asFunctionMethod;
   final Procedure asFunctionInternal;
+  final Procedure sizeOfMethod;
   final Procedure lookupFunctionMethod;
   final Procedure fromFunctionMethod;
   final Field addressOfField;
@@ -282,10 +285,15 @@
             index.getMember('dart:ffi', 'Struct', '_fromPointer'),
         fromAddressInternal =
             index.getTopLevelMember('dart:ffi', '_fromAddress'),
+        structPointerRef =
+            index.getMember('dart:ffi', 'StructPointer', 'get:ref'),
+        structPointerElemAt =
+            index.getMember('dart:ffi', 'StructPointer', '[]'),
         asFunctionMethod =
             index.getMember('dart:ffi', 'NativeFunctionPointer', 'asFunction'),
         asFunctionInternal =
             index.getTopLevelMember('dart:ffi', '_asFunctionInternal'),
+        sizeOfMethod = index.getTopLevelMember('dart:ffi', 'sizeOf'),
         lookupFunctionMethod = index.getMember(
             'dart:ffi', 'DynamicLibraryExtension', 'lookupFunction'),
         fromFunctionMethod =
@@ -344,7 +352,9 @@
   /// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
   ///    where DartRepresentationOf(Tn) -> Sn
   DartType convertNativeTypeToDartType(DartType nativeType,
-      {bool allowStructs = false, bool allowHandle = false}) {
+      {bool allowStructs = false,
+      bool allowStructItself = false,
+      bool allowHandle = false}) {
     if (nativeType is! InterfaceType) {
       return null;
     }
@@ -353,6 +363,9 @@
     final NativeType nativeType_ = getType(nativeClass);
 
     if (hierarchy.isSubclassOf(nativeClass, structClass)) {
+      if (structClass == nativeClass) {
+        return allowStructItself ? nativeType : null;
+      }
       return allowStructs ? nativeType : null;
     }
     if (nativeType_ == null) {
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index 6970c22..853087e 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -9,6 +9,7 @@
 import 'package:front_end/src/api_unstable/vm.dart'
     show
         templateFfiEmptyStruct,
+        templateFfiEmptyStructWarning,
         templateFfiFieldAnnotation,
         templateFfiFieldCyclic,
         templateFfiFieldNoAnnotation,
@@ -418,6 +419,11 @@
 
     _annoteStructWithFields(node, classes);
     if (classes.isEmpty) {
+      diagnosticReporter.report(
+          templateFfiEmptyStructWarning.withArguments(node.name),
+          node.fileOffset,
+          node.name.length,
+          node.location.file);
       emptyStructs.add(node);
     }
 
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 7bfd6a2..e963078 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -13,6 +13,7 @@
         templateFfiExpectedExceptionalReturn,
         templateFfiExpectedNoExceptionalReturn,
         templateFfiExtendsOrImplementsSealedClass,
+        templateFfiNonConstantTypeArgumentWarning,
         templateFfiNotStatic,
         templateFfiTypeInvalid,
         templateFfiTypeMismatch;
@@ -173,7 +174,23 @@
 
     final Member target = node.target;
     try {
-      if (target == lookupFunctionMethod) {
+      if (target == structPointerRef || target == structPointerElemAt) {
+        final DartType nativeType = node.arguments.types[0];
+
+        _warningNativeTypeValid(nativeType, node, allowStructItself: false);
+
+        // TODO(http://dartbug.com/38721): Replace calls with direct
+        // constructor invocations.
+      } else if (target == sizeOfMethod) {
+        final DartType nativeType = node.arguments.types[0];
+
+        if (!isFfiLibrary) {
+          _warningNativeTypeValid(nativeType, node);
+        }
+
+        // TODO(http://dartbug.com/38721): Replace calls with constant
+        // expressions.
+      } else if (target == lookupFunctionMethod) {
         final DartType nativeType = InterfaceType(
             nativeFunctionClass, Nullability.legacy, [node.arguments.types[0]]);
         final DartType dartType = node.arguments.types[1];
@@ -376,6 +393,9 @@
         final DartType pointerType =
             node.receiver.getStaticType(_staticTypeContext);
         final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
+
+        _warningNativeTypeValid(nativeType, node);
+
         if (nativeType is TypeParameterType) {
           // Do not rewire generic invocations.
           return node;
@@ -427,9 +447,11 @@
   }
 
   void _ensureNativeTypeValid(DartType nativeType, Expression node,
-      {bool allowHandle: false}) {
+      {bool allowHandle: false, bool allowStructItself = true}) {
     if (!_nativeTypeValid(nativeType,
-        allowStructs: true, allowHandle: allowHandle)) {
+        allowStructs: true,
+        allowStructItself: allowStructItself,
+        allowHandle: allowHandle)) {
       diagnosticReporter.report(
           templateFfiTypeInvalid.withArguments(
               nativeType, currentLibrary.isNonNullableByDefault),
@@ -440,6 +462,22 @@
     }
   }
 
+  void _warningNativeTypeValid(DartType nativeType, Expression node,
+      {bool allowHandle: false, bool allowStructItself = true}) {
+    if (!_nativeTypeValid(nativeType,
+        allowStructs: true,
+        allowStructItself: allowStructItself,
+        allowHandle: allowHandle)) {
+      diagnosticReporter.report(
+          templateFfiNonConstantTypeArgumentWarning.withArguments(
+              nativeType, currentLibrary.isNonNullableByDefault),
+          node.fileOffset,
+          1,
+          node.location.file);
+      throw _FfiStaticTypeError();
+    }
+  }
+
   void _ensureNoEmptyStructs(DartType nativeType, Expression node) {
     // Error on structs with no fields.
     if (nativeType is InterfaceType) {
@@ -466,9 +504,13 @@
   /// The Dart type system does not enforce that NativeFunction return and
   /// parameter types are only NativeTypes, so we need to check this.
   bool _nativeTypeValid(DartType nativeType,
-      {bool allowStructs: false, allowHandle: false}) {
+      {bool allowStructs: false,
+      bool allowStructItself = false,
+      bool allowHandle = false}) {
     return convertNativeTypeToDartType(nativeType,
-            allowStructs: allowStructs, allowHandle: allowHandle) !=
+            allowStructs: allowStructs,
+            allowStructItself: allowStructItself,
+            allowHandle: allowHandle) !=
         null;
   }
 
diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
index eb87192..84d68ad 100644
--- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -64,10 +64,7 @@
       maturity: Maturity.UNSTABLE,
       dart2jsPatchPath: "_internal/js_runtime/lib/developer_patch.dart"),
   "ffi": const LibraryInfo("ffi/ffi.dart",
-      categories: "Server",
-      // TODO(dacoharkes): Update maturity when we release dart:ffi.
-      // https://github.com/dart-lang/sdk/issues/34452
-      maturity: Maturity.EXPERIMENTAL),
+      categories: "Server", maturity: Maturity.STABLE),
   "html": const LibraryInfo("html/dart2js/html_dart2js.dart",
       categories: "Client",
       maturity: Maturity.WEB_STABLE,
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index bce5feb..22ea459 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -5,8 +5,6 @@
 /**
  * Foreign Function Interface for interoperability with the C programming language.
  *
- * **NOTE**: Dart:FFI is in beta, and breaking API changes might still happen.
- *
  * For further details, please see: https://dart.dev/server/c-interop
  *
  * {@category VM}
@@ -25,6 +23,10 @@
 /// Number of bytes used by native type T.
 ///
 /// Includes padding and alignment of structs.
+///
+/// Support for invoking this function with non-constant [T] will be removed in
+/// the next stable version of Dart and it will become mandatory to invoke it
+/// with a compile-time constant [T].
 external int sizeOf<T extends NativeType>();
 
 /// Represents a pointer into the native C memory corresponding to "NULL", e.g.
@@ -62,6 +64,10 @@
   external int get address;
 
   /// Pointer arithmetic (takes element size into account).
+  ///
+  /// Support for invoking this method with non-constant [T] will be removed in
+  /// the next stable version of Dart and it will become mandatory to invoke it
+  /// with a compile-time constant [T].
   external Pointer<T> elementAt(int index);
 
   /// Cast Pointer<T> to a Pointer<V>.
@@ -538,6 +544,10 @@
   ///
   /// The [address] must be aligned according to the struct alignment rules of
   /// the platform.
+  ///
+  /// Support for invoking this extension method with non-constant [T] will be
+  /// removed in the next stable version of Dart and it will become mandatory
+  /// to invoke it with a compile-time constant [T].
   external T get ref;
 
   /// Creates a reference to access the fields of this struct backed by native
@@ -545,6 +555,10 @@
   ///
   /// The [address] must be aligned according to the struct alignment rules of
   /// the platform.
+  ///
+  /// Support for invoking this extension method with non-constant [T] will be
+  /// removed in the next stable version of Dart and it will become mandatory
+  /// to invoke it with a compile-time constant [T].
   external T operator [](int index);
 }
 
diff --git a/sdk/lib/io/common.dart b/sdk/lib/io/common.dart
index 9688d8d..252d602 100644
--- a/sdk/lib/io/common.dart
+++ b/sdk/lib/io/common.dart
@@ -19,9 +19,7 @@
 bool _isErrorResponse(response) =>
     response is List && response[0] != _successResponse;
 
-/**
- * Returns an Exception or an Error
- */
+/// Returns an [Exception] or an [Error].
 _exceptionFromResponse(response, String message, String path) {
   assert(_isErrorResponse(response));
   switch (response[_errorResponseErrorType]) {
@@ -38,20 +36,16 @@
   }
 }
 
-/**
- * Base class for all IO related exceptions.
- */
+/// Base class for all IO related exceptions.
 abstract class IOException implements Exception {
   String toString() => "IOException";
 }
 
-/**
-  * An [OSError] object holds information about an error from the
-  * operating system.
-  */
+/// An [Exception] holding information about an error from the
+/// operating system.
 @pragma("vm:entry-point")
 class OSError implements Exception {
-  /** Constant used to indicate that no OS error code is available. */
+  /// Constant used to indicate that no OS error code is available.
   static const int noErrorCode = -1;
 
   /// Error message supplied by the operating system. This will be empty if no
@@ -64,11 +58,11 @@
   /// associated with the error.
   final int errorCode;
 
-  /** Creates an OSError object from a message and an errorCode. */
+  /// Creates an OSError object from a message and an errorCode.
   @pragma("vm:entry-point")
   const OSError([this.message = "", this.errorCode = noErrorCode]);
 
-  /** Converts an OSError object to a string representation. */
+  /// Converts an OSError object to a string representation.
   String toString() {
     StringBuffer sb = new StringBuffer();
     sb.write("OS Error");
diff --git a/sdk/lib/io/data_transformer.dart b/sdk/lib/io/data_transformer.dart
index 4346a1a..0928116 100644
--- a/sdk/lib/io/data_transformer.dart
+++ b/sdk/lib/io/data_transformer.dart
@@ -4,11 +4,9 @@
 
 part of dart.io;
 
-/**
- * Exposes ZLib options for input parameters.
- *
- * See http://www.zlib.net/manual.html for more documentation.
- */
+/// Exposes ZLib options for input parameters.
+///
+/// See http://www.zlib.net/manual.html for more documentation.
 abstract class ZLibOption {
   /// Minimal value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits]
   /// and [ZLibDecoder.windowBits].
@@ -85,84 +83,67 @@
   static const int STRATEGY_DEFAULT = 0;
 }
 
-/**
- * An instance of the default implementation of the [ZLibCodec].
- */
+/// An instance of the default implementation of the [ZLibCodec].
 const ZLibCodec zlib = const ZLibCodec._default();
 @Deprecated("Use zlib instead")
 const ZLibCodec ZLIB = zlib;
 
-/**
- * The [ZLibCodec] encodes raw bytes to ZLib compressed bytes and decodes ZLib
- * compressed bytes to raw bytes.
- */
+/// The [ZLibCodec] encodes raw bytes to ZLib compressed bytes and decodes ZLib
+/// compressed bytes to raw bytes.
 class ZLibCodec extends Codec<List<int>, List<int>> {
-  /**
-   * When true, `GZip` frames will be added to the compressed data.
-   */
+  /// When true, `GZip` frames will be added to the compressed data.
   final bool gzip;
 
-  /**
-   * The compression-[level] can be set in the range of `-1..9`, with `6` being
-   * the default compression level. Levels above `6` will have higher
-   * compression rates at the cost of more CPU and memory usage. Levels below
-   * `6` will use less CPU and memory at the cost of lower compression rates.
-   */
+  /// The compression-[level] can be set in the range of `-1..9`, with `6` being
+  /// the default compression level. Levels above `6` will have higher
+  /// compression rates at the cost of more CPU and memory usage. Levels below
+  /// `6` will use less CPU and memory at the cost of lower compression rates.
   final int level;
 
-  /**
-   * Specifies how much memory should be allocated for the internal compression
-   * state. `1` uses minimum memory but is slow and reduces compression ratio;
-   * `9` uses maximum memory for optimal speed. The default value is `8`.
-   *
-   * The memory requirements for deflate are (in bytes):
-   *
-   *     (1 << (windowBits + 2)) +  (1 << (memLevel + 9))
-   * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
-   */
+  /// Specifies how much memory should be allocated for the internal compression
+  /// state. `1` uses minimum memory but is slow and reduces compression ratio;
+  /// `9` uses maximum memory for optimal speed. The default value is `8`.
+  ///
+  /// The memory requirements for deflate are (in bytes):
+  /// ```dart
+  /// (1 << (windowBits + 2)) +  (1 << (memLevel + 9))
+  /// ```
+  /// that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
   final int memLevel;
 
-  /**
-   * Tunes the compression algorithm. Use the value strategyDefault for normal
-   * data, strategyFiltered for data produced by a filter (or predictor),
-   * strategyHuffmanOnly to force Huffman encoding only (no string match), or
-   * strategyRle to limit match distances to one (run-length encoding).
-   */
+  /// Tunes the compression algorithm. Use the value strategyDefault for normal
+  /// data, strategyFiltered for data produced by a filter (or predictor),
+  /// strategyHuffmanOnly to force Huffman encoding only (no string match), or
+  /// strategyRle to limit match distances to one (run-length encoding).
   final int strategy;
 
-  /**
-   * Base two logarithm of the window size (the size of the history buffer). It
-   * should be in the range 8..15. Larger values result in better compression at
-   * the expense of memory usage. The default value is 15
-   */
+  /// Base two logarithm of the window size (the size of the history buffer). It
+  /// should be in the range 8..15. Larger values result in better compression at
+  /// the expense of memory usage. The default value is 15
   final int windowBits;
 
-  /**
-   * When true, deflate generates raw data with no zlib header or trailer, and
-   * will not compute an adler32 check value
-   */
+  /// When true, deflate generates raw data with no zlib header or trailer, and
+  /// will not compute an adler32 check value
   final bool raw;
 
-  /**
-   * Initial compression dictionary.
-   *
-   * It should consist of strings (byte sequences) that are likely to be
-   * encountered later in the data to be compressed, with the most commonly used
-   * strings preferably put towards the end of the dictionary. Using a
-   * dictionary is most useful when the data to be compressed is short and can
-   * be predicted with good accuracy; the data can then be compressed better
-   * than with the default empty dictionary.
-   */
+  /// Initial compression dictionary.
+  ///
+  /// It should consist of strings (byte sequences) that are likely to be
+  /// encountered later in the data to be compressed, with the most commonly used
+  /// strings preferably put towards the end of the dictionary. Using a
+  /// dictionary is most useful when the data to be compressed is short and can
+  /// be predicted with good accuracy; the data can then be compressed better
+  /// than with the default empty dictionary.
   final List<int>? dictionary;
 
   ZLibCodec(
-      {this.level: ZLibOption.defaultLevel,
-      this.windowBits: ZLibOption.defaultWindowBits,
-      this.memLevel: ZLibOption.defaultMemLevel,
-      this.strategy: ZLibOption.strategyDefault,
+      {this.level = ZLibOption.defaultLevel,
+      this.windowBits = ZLibOption.defaultWindowBits,
+      this.memLevel = ZLibOption.defaultMemLevel,
+      this.strategy = ZLibOption.strategyDefault,
       this.dictionary,
-      this.raw: false,
-      this.gzip: false}) {
+      this.raw = false,
+      this.gzip = false}) {
     _validateZLibeLevel(level);
     _validateZLibMemLevel(memLevel);
     _validateZLibStrategy(strategy);
@@ -178,9 +159,7 @@
         gzip = false,
         dictionary = null;
 
-  /**
-   * Get a [ZLibEncoder] for encoding to `ZLib` compressed data.
-   */
+  /// Get a [ZLibEncoder] for encoding to `ZLib` compressed data.
   ZLibEncoder get encoder => new ZLibEncoder(
       gzip: false,
       level: level,
@@ -190,96 +169,77 @@
       dictionary: dictionary,
       raw: raw);
 
-  /**
-   * Get a [ZLibDecoder] for decoding `ZLib` compressed data.
-   */
+  /// Get a [ZLibDecoder] for decoding `ZLib` compressed data.
   ZLibDecoder get decoder =>
       new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw);
 }
 
-/**
- * An instance of the default implementation of the [GZipCodec].
- */
+/// An instance of the default implementation of the [GZipCodec].
 const GZipCodec gzip = const GZipCodec._default();
 @Deprecated("Use gzip instead")
 const GZipCodec GZIP = gzip;
 
-/**
- * The [GZipCodec] encodes raw bytes to GZip compressed bytes and decodes GZip
- * compressed bytes to raw bytes.
- *
- * The difference between [ZLibCodec] and [GZipCodec] is that the [GZipCodec]
- * wraps the `ZLib` compressed bytes in `GZip` frames.
- */
+/// The [GZipCodec] encodes raw bytes to GZip compressed bytes and decodes GZip
+/// compressed bytes to raw bytes.
+///
+/// The difference between [ZLibCodec] and [GZipCodec] is that the [GZipCodec]
+/// wraps the `ZLib` compressed bytes in `GZip` frames.
 class GZipCodec extends Codec<List<int>, List<int>> {
-  /**
-   * When true, `GZip` frames will be added to the compressed data.
-   */
+  /// When true, `GZip` frames will be added to the compressed data.
   final bool gzip;
 
-  /**
-   * The compression-[level] can be set in the range of `-1..9`, with `6` being
-   * the default compression level. Levels above `6` will have higher
-   * compression rates at the cost of more CPU and memory usage. Levels below
-   * `6` will use less CPU and memory at the cost of lower compression rates.
-   */
+  /// The compression-[level] can be set in the range of `-1..9`, with `6` being
+  /// the default compression level. Levels above `6` will have higher
+  /// compression rates at the cost of more CPU and memory usage. Levels below
+  /// `6` will use less CPU and memory at the cost of lower compression rates.
   final int level;
 
-  /**
-   * Specifies how much memory should be allocated for the internal compression
-   * state. `1` uses minimum memory but is slow and reduces compression ratio;
-   * `9` uses maximum memory for optimal speed. The default value is `8`.
-   *
-   * The memory requirements for deflate are (in bytes):
-   *
-   *     (1 << (windowBits + 2)) +  (1 << (memLevel + 9))
-   * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
-   */
+  /// Specifies how much memory should be allocated for the internal compression
+  /// state. `1` uses minimum memory but is slow and reduces compression ratio;
+  /// `9` uses maximum memory for optimal speed. The default value is `8`.
+  ///
+  /// The memory requirements for deflate are (in bytes):
+  /// ```dart
+  /// (1 << (windowBits + 2)) +  (1 << (memLevel + 9))
+  /// ```
+  /// that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
   final int memLevel;
 
-  /**
-   * Tunes the compression algorithm. Use the value
-   * [ZLibOption.strategyDefault] for normal data,
-   * [ZLibOption.strategyFiltered] for data produced by a filter
-   * (or predictor), [ZLibOption.strategyHuffmanOnly] to force Huffman
-   * encoding only (no string match), or [ZLibOption.strategyRle] to limit
-   * match distances to one (run-length encoding).
-   */
+  /// Tunes the compression algorithm. Use the value
+  /// [ZLibOption.strategyDefault] for normal data,
+  /// [ZLibOption.strategyFiltered] for data produced by a filter
+  /// (or predictor), [ZLibOption.strategyHuffmanOnly] to force Huffman
+  /// encoding only (no string match), or [ZLibOption.strategyRle] to limit
+  /// match distances to one (run-length encoding).
   final int strategy;
 
-  /**
-   * Base two logarithm of the window size (the size of the history buffer). It
-   * should be in the range `8..15`. Larger values result in better compression
-   * at the expense of memory usage. The default value is `15`
-   */
+  /// Base two logarithm of the window size (the size of the history buffer). It
+  /// should be in the range `8..15`. Larger values result in better compression
+  /// at the expense of memory usage. The default value is `15`
   final int windowBits;
 
-  /**
-   * Initial compression dictionary.
-   *
-   * It should consist of strings (byte sequences) that are likely to be
-   * encountered later in the data to be compressed, with the most commonly used
-   * strings preferably put towards the end of the dictionary. Using a
-   * dictionary is most useful when the data to be compressed is short and can
-   * be predicted with good accuracy; the data can then be compressed better
-   * than with the default empty dictionary.
-   */
+  /// Initial compression dictionary.
+  ///
+  /// It should consist of strings (byte sequences) that are likely to be
+  /// encountered later in the data to be compressed, with the most commonly used
+  /// strings preferably put towards the end of the dictionary. Using a
+  /// dictionary is most useful when the data to be compressed is short and can
+  /// be predicted with good accuracy; the data can then be compressed better
+  /// than with the default empty dictionary.
   final List<int>? dictionary;
 
-  /**
-   * When true, deflate generates raw data with no zlib header or trailer, and
-   * will not compute an adler32 check value
-   */
+  /// When true, deflate generates raw data with no zlib header or trailer, and
+  /// will not compute an adler32 check value
   final bool raw;
 
   GZipCodec(
-      {this.level: ZLibOption.defaultLevel,
-      this.windowBits: ZLibOption.defaultWindowBits,
-      this.memLevel: ZLibOption.defaultMemLevel,
-      this.strategy: ZLibOption.strategyDefault,
+      {this.level = ZLibOption.defaultLevel,
+      this.windowBits = ZLibOption.defaultWindowBits,
+      this.memLevel = ZLibOption.defaultMemLevel,
+      this.strategy = ZLibOption.strategyDefault,
       this.dictionary,
-      this.raw: false,
-      this.gzip: true}) {
+      this.raw = false,
+      this.gzip = true}) {
     _validateZLibeLevel(level);
     _validateZLibMemLevel(memLevel);
     _validateZLibStrategy(strategy);
@@ -295,9 +255,7 @@
         gzip = true,
         dictionary = null;
 
-  /**
-   * Get a [ZLibEncoder] for encoding to `GZip` compressed data.
-   */
+  /// Get a [ZLibEncoder] for encoding to `GZip` compressed data.
   ZLibEncoder get encoder => new ZLibEncoder(
       gzip: true,
       level: level,
@@ -307,96 +265,77 @@
       dictionary: dictionary,
       raw: raw);
 
-  /**
-   * Get a [ZLibDecoder] for decoding `GZip` compressed data.
-   */
+  /// Get a [ZLibDecoder] for decoding `GZip` compressed data.
   ZLibDecoder get decoder =>
       new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw);
 }
 
-/**
- * The [ZLibEncoder] encoder is used by [ZLibCodec] and [GZipCodec] to compress
- * data.
- */
+/// The [ZLibEncoder] encoder is used by [ZLibCodec] and [GZipCodec] to compress
+/// data.
 class ZLibEncoder extends Converter<List<int>, List<int>> {
-  /**
-   * When true, `GZip` frames will be added to the compressed data.
-   */
+  /// When true, `GZip` frames will be added to the compressed data.
   final bool gzip;
 
-  /**
-   * The compression-[level] can be set in the range of `-1..9`, with `6` being
-   * the default compression level. Levels above `6` will have higher
-   * compression rates at the cost of more CPU and memory usage. Levels below
-   * `6` will use less CPU and memory at the cost of lower compression rates.
-   */
+  /// The compression-[level] can be set in the range of `-1..9`, with `6` being
+  /// the default compression level. Levels above `6` will have higher
+  /// compression rates at the cost of more CPU and memory usage. Levels below
+  /// `6` will use less CPU and memory at the cost of lower compression rates.
   final int level;
 
-  /**
-   * Specifies how much memory should be allocated for the internal compression
-   * state. `1` uses minimum memory but is slow and reduces compression ratio;
-   * `9` uses maximum memory for optimal speed. The default value is `8`.
-   *
-   * The memory requirements for deflate are (in bytes):
-   *
-   *     (1 << (windowBits + 2)) +  (1 << (memLevel + 9))
-   * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
-   */
+  /// Specifies how much memory should be allocated for the internal compression
+  /// state. `1` uses minimum memory but is slow and reduces compression ratio;
+  /// `9` uses maximum memory for optimal speed. The default value is `8`.
+  ///
+  /// The memory requirements for deflate are (in bytes):
+  /// ```dart
+  /// (1 << (windowBits + 2)) +  (1 << (memLevel + 9))
+  /// ```
+  /// that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
   final int memLevel;
 
-  /**
-   * Tunes the compression algorithm. Use the value
-   * [ZLibOption.strategyDefault] for normal data,
-   * [ZLibOption.strategyFiltered] for data produced by a filter
-   * (or predictor), [ZLibOption.strategyHuffmanOnly] to force Huffman
-   * encoding only (no string match), or [ZLibOption.strategyRle] to limit
-   * match distances to one (run-length encoding).
-   */
+  /// Tunes the compression algorithm. Use the value
+  /// [ZLibOption.strategyDefault] for normal data,
+  /// [ZLibOption.strategyFiltered] for data produced by a filter
+  /// (or predictor), [ZLibOption.strategyHuffmanOnly] to force Huffman
+  /// encoding only (no string match), or [ZLibOption.strategyRle] to limit
+  /// match distances to one (run-length encoding).
   final int strategy;
 
-  /**
-   * Base two logarithm of the window size (the size of the history buffer). It
-   * should be in the range `8..15`. Larger values result in better compression
-   * at the expense of memory usage. The default value is `15`
-   */
+  /// Base two logarithm of the window size (the size of the history buffer). It
+  /// should be in the range `8..15`. Larger values result in better compression
+  /// at the expense of memory usage. The default value is `15`
   final int windowBits;
 
-  /**
-   * Initial compression dictionary.
-   *
-   * It should consist of strings (byte sequences) that are likely to be
-   * encountered later in the data to be compressed, with the most commonly used
-   * strings preferably put towards the end of the dictionary. Using a
-   * dictionary is most useful when the data to be compressed is short and can
-   * be predicted with good accuracy; the data can then be compressed better
-   * than with the default empty dictionary.
-   */
+  /// Initial compression dictionary.
+  ///
+  /// It should consist of strings (byte sequences) that are likely to be
+  /// encountered later in the data to be compressed, with the most commonly used
+  /// strings preferably put towards the end of the dictionary. Using a
+  /// dictionary is most useful when the data to be compressed is short and can
+  /// be predicted with good accuracy; the data can then be compressed better
+  /// than with the default empty dictionary.
   final List<int>? dictionary;
 
-  /**
-   * When true, deflate generates raw data with no zlib header or trailer, and
-   * will not compute an adler32 check value
-   */
+  /// When true, deflate generates raw data with no zlib header or trailer, and
+  /// will not compute an adler32 check value
   final bool raw;
 
   ZLibEncoder(
-      {this.gzip: false,
-      this.level: ZLibOption.defaultLevel,
-      this.windowBits: ZLibOption.defaultWindowBits,
-      this.memLevel: ZLibOption.defaultMemLevel,
-      this.strategy: ZLibOption.strategyDefault,
+      {this.gzip = false,
+      this.level = ZLibOption.defaultLevel,
+      this.windowBits = ZLibOption.defaultWindowBits,
+      this.memLevel = ZLibOption.defaultMemLevel,
+      this.strategy = ZLibOption.strategyDefault,
       this.dictionary,
-      this.raw: false}) {
+      this.raw = false}) {
     _validateZLibeLevel(level);
     _validateZLibMemLevel(memLevel);
     _validateZLibStrategy(strategy);
     _validateZLibWindowBits(windowBits);
   }
 
-  /**
-   * Convert a list of bytes using the options given to the ZLibEncoder
-   * constructor.
-   */
+  /// Convert a list of bytes using the options given to the ZLibEncoder
+  /// constructor.
   List<int> convert(List<int> bytes) {
     _BufferSink sink = new _BufferSink();
     startChunkedConversion(sink)
@@ -405,11 +344,12 @@
     return sink.builder.takeBytes();
   }
 
-  /**
-   * Start a chunked conversion using the options given to the [ZLibEncoder]
-   * constructor. While it accepts any [Sink] taking [List<int>]'s,
-   * the optimal sink to be passed as [sink] is a [ByteConversionSink].
-   */
+  /// Start a chunked conversion using the options given to the [ZLibEncoder]
+  /// constructor.
+  ///
+  /// Accepts any `Sink<List<int>>`, but prefers a [ByteConversionSink],
+  /// and converts any other sink to a [ByteConversionSink] before
+  /// using it.
   ByteConversionSink startChunkedConversion(Sink<List<int>> sink) {
     if (sink is! ByteConversionSink) {
       sink = new ByteConversionSink.from(sink);
@@ -419,46 +359,36 @@
   }
 }
 
-/**
- * The [ZLibDecoder] is used by [ZLibCodec] and [GZipCodec] to decompress data.
- */
+/// The [ZLibDecoder] is used by [ZLibCodec] and [GZipCodec] to decompress data.
 class ZLibDecoder extends Converter<List<int>, List<int>> {
-  /**
-   * Base two logarithm of the window size (the size of the history buffer). It
-   * should be in the range `8..15`. Larger values result in better compression
-   * at the expense of memory usage. The default value is `15`.
-   */
+  /// Base two logarithm of the window size (the size of the history buffer). It
+  /// should be in the range `8..15`. Larger values result in better compression
+  /// at the expense of memory usage. The default value is `15`.
   final int windowBits;
 
-  /**
-   * Initial compression dictionary.
-   *
-   * It should consist of strings (byte sequences) that are likely to be
-   * encountered later in the data to be compressed, with the most commonly used
-   * strings preferably put towards the end of the dictionary. Using a
-   * dictionary is most useful when the data to be compressed is short and can
-   * be predicted with good accuracy; the data can then be compressed better
-   * than with the default empty dictionary.
-   */
+  /// Initial compression dictionary.
+  ///
+  /// It should consist of strings (byte sequences) that are likely to be
+  /// encountered later in the data to be compressed, with the most commonly used
+  /// strings preferably put towards the end of the dictionary. Using a
+  /// dictionary is most useful when the data to be compressed is short and can
+  /// be predicted with good accuracy; the data can then be compressed better
+  /// than with the default empty dictionary.
   final List<int>? dictionary;
 
-  /**
-   * When true, deflate generates raw data with no zlib header or trailer, and
-   * will not compute an adler32 check value
-   */
+  /// When true, deflate generates raw data with no zlib header or trailer, and
+  /// will not compute an adler32 check value
   final bool raw;
 
   ZLibDecoder(
-      {this.windowBits: ZLibOption.defaultWindowBits,
+      {this.windowBits = ZLibOption.defaultWindowBits,
       this.dictionary,
-      this.raw: false}) {
+      this.raw = false}) {
     _validateZLibWindowBits(windowBits);
   }
 
-  /**
-   * Convert a list of bytes using the options given to the [ZLibDecoder]
-   * constructor.
-   */
+  /// Convert a list of bytes using the options given to the [ZLibDecoder]
+  /// constructor.
   List<int> convert(List<int> bytes) {
     _BufferSink sink = new _BufferSink();
     startChunkedConversion(sink)
@@ -467,11 +397,11 @@
     return sink.builder.takeBytes();
   }
 
-  /**
-   * Start a chunked conversion. While it accepts any [Sink]
-   * taking [List<int>]'s, the optimal sink to be passed as [sink] is a
-   * [ByteConversionSink].
-   */
+  /// Start a chunked conversion.
+  ///
+  /// Accepts any `Sink<List<int>>`, but prefers a [ByteConversionSink],
+  /// and converts any other sink to a [ByteConversionSink] before
+  /// using it.
   ByteConversionSink startChunkedConversion(Sink<List<int>> sink) {
     if (sink is! ByteConversionSink) {
       sink = new ByteConversionSink.from(sink);
@@ -480,54 +410,48 @@
   }
 }
 
-/**
- * The [RawZLibFilter] class provides a low-level interface to zlib.
- */
+/// The [RawZLibFilter] class provides a low-level interface to zlib.
 abstract class RawZLibFilter {
-  /**
-   * Returns a a [RawZLibFilter] whose [process] and [processed] methods
-   * compress data.
-   */
+  /// Returns a a [RawZLibFilter] whose [process] and [processed] methods
+  /// compress data.
   factory RawZLibFilter.deflateFilter({
-    bool gzip: false,
-    int level: ZLibOption.defaultLevel,
-    int windowBits: ZLibOption.defaultWindowBits,
-    int memLevel: ZLibOption.defaultMemLevel,
-    int strategy: ZLibOption.strategyDefault,
+    bool gzip = false,
+    int level = ZLibOption.defaultLevel,
+    int windowBits = ZLibOption.defaultWindowBits,
+    int memLevel = ZLibOption.defaultMemLevel,
+    int strategy = ZLibOption.strategyDefault,
     List<int>? dictionary,
-    bool raw: false,
+    bool raw = false,
   }) {
     return _makeZLibDeflateFilter(
         gzip, level, windowBits, memLevel, strategy, dictionary, raw);
   }
 
-  /**
-   * Returns a a [RawZLibFilter] whose [process] and [processed] methods
-   * decompress data.
-   */
+  /// Returns a a [RawZLibFilter] whose [process] and [processed] methods
+  /// decompress data.
   factory RawZLibFilter.inflateFilter({
-    int windowBits: ZLibOption.defaultWindowBits,
+    int windowBits = ZLibOption.defaultWindowBits,
     List<int>? dictionary,
-    bool raw: false,
+    bool raw = false,
   }) {
     return _makeZLibInflateFilter(windowBits, dictionary, raw);
   }
 
-  /**
-   * Call to process a chunk of data. A call to [process] should only be made
-   * when [processed] returns [:null:].
-   */
+  /// Process a chunk of data.
+  ///
+  /// This method must only be called when [processed] returns `null`.
   void process(List<int> data, int start, int end);
 
-  /**
-   * Get a chunk of processed data. When there are no more data available,
-   * [processed] will return [:null:]. Set [flush] to [:false:] for non-final
-   * calls to improve performance of some filters.
-   *
-   * The last call to [processed] should have [end] set to [:true:]. This will
-   * make sure an 'end' packet is written on the stream.
-   */
-  List<int>? processed({bool flush: true, bool end: false});
+  /// Get a chunk of processed data.
+  ///
+  /// When there are no more data available, [processed] will return `null`.
+  /// Set [flush] to `false` for non-final calls
+  /// to improve performance of some filters.
+  ///
+  /// The last call to [processed] should have [end] set to `true`. This will
+  /// make sure an 'end' packet is written on the stream.
+  // TODO: Which stream?
+  List<int>? processed({bool flush = true, bool end = false});
 
   external static RawZLibFilter _makeZLibDeflateFilter(
       bool gzip,
diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart
index ee8ef1d..dbbcb26 100644
--- a/sdk/lib/io/directory.dart
+++ b/sdk/lib/io/directory.dart
@@ -4,124 +4,110 @@
 
 part of dart.io;
 
-/**
- * A reference to a directory (or _folder_) on the file system.
- *
- * A Directory instance is an object holding a [path] on which operations can
- * be performed. The path to the directory can be [absolute] or relative.
- * You can get the parent directory using the getter [parent],
- * a property inherited from [FileSystemEntity].
- *
- * In addition to being used as an instance to access the file system,
- * Directory has a number of static properties, such as [systemTemp],
- * which gets the system's temporary directory, and the getter and setter
- * [current], which you can use to access or change the current directory.
- *
- * Create a new Directory object with a pathname to access the specified
- * directory on the file system from your program.
- *
- *     var myDir = new Directory('myDir');
- *
- * Most methods in this class occur in synchronous and asynchronous pairs,
- * for example, [create] and [createSync].
- * Unless you have a specific reason for using the synchronous version
- * of a method, prefer the asynchronous version to avoid blocking your program.
- *
- * ## Create a directory
- *
- * The following code sample creates a directory using the [create] method.
- * By setting the `recursive` parameter to true, you can create the
- * named directory and all its necessary parent directories,
- * if they do not already exist.
- *
- *     import 'dart:io';
- *
- *     void main() {
- *       // Creates dir/ and dir/subdir/.
- *       new Directory('dir/subdir').create(recursive: true)
- *         // The created directory is returned as a Future.
- *         .then((Directory directory) {
- *           print(directory.path);
- *       });
- *     }
- *
- * ## List a directory
- *
- * Use the [list] or [listSync] methods to get the files and directories
- * contained by a directory.
- * Set `recursive` to true to recursively list all subdirectories.
- * Set `followLinks` to true to follow symbolic links.
- * The list method returns a [Stream] that provides FileSystemEntity
- * objects. Use the listen callback function to process each object
- * as it become available.
- *
- *     import 'dart:io';
- *
- *     void main() {
- *       // Get the system temp directory.
- *       var systemTempDir = Directory.systemTemp;
- *
- *       // List directory contents, recursing into sub-directories,
- *       // but not following symbolic links.
- *       systemTempDir.list(recursive: true, followLinks: false)
- *         .listen((FileSystemEntity entity) {
- *           print(entity.path);
- *         });
- *     }
- *
- * ## The use of Futures
- *
- * I/O operations can block a program for some period of time while it waits for
- * the operation to complete. To avoid this, all
- * methods involving I/O have an asynchronous variant which returns a [Future].
- * This future completes when the I/O operation finishes. While the I/O
- * operation is in progress, the Dart program is not blocked,
- * and can perform other operations.
- *
- * For example,
- * the [exists] method, which determines whether the directory exists,
- * returns a boolean value using a Future.
- * Use `then` to register a callback function, which is called when
- * the value is ready.
- *
- *     import 'dart:io';
- *
- *     main() {
- *       final myDir = new Directory('dir');
- *       myDir.exists().then((isThere) {
- *         isThere ? print('exists') : print('non-existent');
- *       });
- *     }
- *
- *
- * In addition to exists, the [stat], [rename], and
- * other methods, return Futures.
- *
- * ## Other resources
- *
- * * The [Files and directories](https://dart.dev/guides/libraries/library-tour#files-and-directories)
- *   section of the library tour.
- *
- * * [Write Command-Line Apps](https://dart.dev/tutorials/server/cmdline),
- *   a tutorial about writing command-line apps, includes information about
- *   files and directories.
- */
+/// A reference to a directory (or _folder_) on the file system.
+///
+/// A [Directory] is an object holding a [path] on which operations can
+/// be performed. The path to the directory can be [absolute] or relative.
+/// It allows access to the [parent] directory,
+/// since it is a [FileSystemEntity].
+///
+/// The [Directory] also provides static access to the system's temporary
+/// file directory, [systemTemp], and the ability to access and change
+/// the [current] directory.
+///
+/// Create a new [Directory] to give access the directory with the specified
+/// path:
+/// ```dart
+/// var myDir = Directory('myDir');
+/// ```
+/// Most intance methods of [Directory] exist in both synchronous
+/// and asynchronous variants, for example, [create] and [createSync].
+/// Unless you have a specific reason for using the synchronous version
+/// of a method, prefer the asynchronous version to avoid blocking your program.
+///
+/// ## Create a directory
+///
+/// The following code sample creates a directory using the [create] method.
+/// By setting the `recursive` parameter to true, you can create the
+/// named directory and all its necessary parent directories,
+/// if they do not already exist.
+/// ```dart
+/// import 'dart:io';
+///
+/// void main() async {
+///   // Creates dir/ and dir/subdir/.
+///   var directory = await Directory('dir/subdir').create(recursive: true)
+///   print(directory.path);
+/// }
+/// ```
+/// ## List the entries of a directory
+///
+/// Use the [list] or [listSync] methods to get the files and directories
+/// contained in a directory.
+/// Set `recursive` to true to recursively list all subdirectories.
+/// Set `followLinks` to true to follow symbolic links.
+/// The list method returns a [Stream] of [FileSystemEntity] objects.
+/// Listen on the stream to access each object as it is found:
+/// ```dart
+/// import 'dart:io';
+///
+/// void main() async {
+///   // Get the system temp directory.
+///   var systemTempDir = Directory.systemTemp;
+///
+///   // List directory contents, recursing into sub-directories,
+///   // but not following symbolic links.
+///   await for (var entity in
+///       systemTempDir.list(recursive: true, followLinks: false)) {
+///     print(entity.path);
+///   }
+/// }
+/// ```
+/// ## The use of asynchronnous methods
+///
+/// I/O operations can block a program for some period of time while it waits for
+/// the operation to complete. To avoid this, all
+/// methods involving I/O have an asynchronous variant which returns a [Future].
+/// This future completes when the I/O operation finishes. While the I/O
+/// operation is in progress, the Dart program is not blocked,
+/// and can perform other operations.
+///
+/// For example,
+/// the [exists] method, which determines whether the directory exists,
+/// returns a boolean value asynchronously using a [Future].
+/// ```dart
+/// import 'dart:io';
+///
+/// void main() async {
+///   final myDir = Directory('dir');
+///   var isThere = await myDir.exists();
+///   print(isThere ? 'exists' : 'non-existent');
+/// }
+/// ```
+///
+/// In addition to [exists], the [stat], [rename],
+/// and other methods are also asynchronous.
+///
+/// ## Other resources
+///
+/// * The [Files and directories](https://dart.dev/guides/libraries/library-tour#files-and-directories)
+///   section of the library tour.
+///
+/// * [Write Command-Line Apps](https://dart.dev/tutorials/server/cmdline),
+///   a tutorial about writing command-line apps, includes information about
+///   files and directories.
 @pragma("vm:entry-point")
 abstract class Directory implements FileSystemEntity {
-  /**
-   * Gets the path of this directory.
-   */
+  /// Gets the path of this directory.
   String get path;
 
-  /**
-   * Creates a [Directory] object.
-   *
-   * If [path] is a relative path, it will be interpreted relative to the
-   * current working directory (see [Directory.current]), when used.
-   *
-   * If [path] is an absolute path, it will be immune to changes to the
-   * current working directory.
-   */
+  /// Creates a [Directory] object.
+  ///
+  /// If [path] is a relative path, it will be interpreted relative to the
+  /// current working directory (see [Directory.current]), when used.
+  ///
+  /// If [path] is an absolute path, it will be immune to changes to the
+  /// current working directory.
   @pragma("vm:entry-point")
   factory Directory(String path) {
     final IOOverrides? overrides = IOOverrides.current;
@@ -137,17 +123,13 @@
     return new _Directory.fromRawPath(path);
   }
 
-  /**
-   * Create a Directory object from a URI.
-   *
-   * If [uri] cannot reference a directory this throws [UnsupportedError].
-   */
+  /// Create a [Directory] from a URI.
+  ///
+  /// If [uri] cannot reference a directory this throws [UnsupportedError].
   factory Directory.fromUri(Uri uri) => new Directory(uri.toFilePath());
 
-  /**
-   * Creates a directory object pointing to the current working
-   * directory.
-   */
+  /// Creates a directory object pointing to the current working
+  /// directory.
   static Directory get current {
     final IOOverrides? overrides = IOOverrides.current;
     if (overrides == null) {
@@ -156,33 +138,30 @@
     return overrides.getCurrentDirectory();
   }
 
-  /**
-   * Returns a [Uri] representing the directory's location.
-   *
-   * The returned URI's scheme is always "file" if the entity's [path] is
-   * absolute, otherwise the scheme will be empty.
-   * The returned URI's path always ends in a slash ('/').
-   */
+  /// A [Uri] representing the directory's location.
+  ///
+  /// The URI's scheme is always "file" if the entity's [path] is
+  /// absolute, otherwise the scheme will be empty and the URI relative.
+  /// The URI's path always ends in a slash ('/').
   Uri get uri;
 
-  /**
-   * Sets the current working directory of the Dart process including
-   * all running isolates. The new value set can be either a [Directory]
-   * or a [String].
-   *
-   * The new value is passed to the OS's system call unchanged, so a
-   * relative path passed as the new working directory will be
-   * resolved by the OS.
-   *
-   * Note that setting the current working directory is a synchronous
-   * operation and that it changes the working directory of *all*
-   * isolates.
-   *
-   * Use this with care - especially when working with asynchronous
-   * operations and multiple isolates. Changing the working directory,
-   * while asynchronous operations are pending or when other isolates
-   * are working with the file system, can lead to unexpected results.
-   */
+  /// Sets the current working directory of the Dart process.
+  ///
+  /// This affects all running isolates.
+  /// The new value set can be either a [Directory] or a [String].
+  ///
+  /// The new value is passed to the OS's system call unchanged, so a
+  /// relative path passed as the new working directory will be
+  /// resolved by the OS.
+  ///
+  /// Note that setting the current working directory is a synchronous
+  /// operation and that it changes the working directory of *all*
+  /// isolates.
+  ///
+  /// Use this with care — especially when working with asynchronous
+  /// operations and multiple isolates. Changing the working directory,
+  /// while asynchronous operations are pending or when other isolates
+  /// are working with the file system, can lead to unexpected results.
   static void set current(path) {
     final IOOverrides? overrides = IOOverrides.current;
     if (overrides == null) {
@@ -192,38 +171,32 @@
     overrides.setCurrentDirectory(path);
   }
 
-  /**
-   * Creates the directory with this name.
-   *
-   * If [recursive] is false, only the last directory in the path is
-   * created. If [recursive] is true, all non-existing path components
-   * are created. If the directory already exists nothing is done.
-   *
-   * Returns a [:Future<Directory>:] that completes with this
-   * directory once it has been created. If the directory cannot be
-   * created the future completes with an exception.
-   */
-  Future<Directory> create({bool recursive: false});
+  /// Creates the directory if it doesn't exist.
+  ///
+  /// If [recursive] is false, only the last directory in the path is
+  /// created. If [recursive] is true, all non-existing path components
+  /// are created. If the directory already exists nothing is done.
+  ///
+  /// Returns a `Future<Directory>` that completes with this
+  /// directory once it has been created. If the directory cannot be
+  /// created the future completes with an exception.
+  Future<Directory> create({bool recursive = false});
 
-  /**
-   * Synchronously creates the directory with this name.
-   *
-   * If [recursive] is false, only the last directory in the path is
-   * created. If [recursive] is true, all non-existing path components
-   * are created. If the directory already exists nothing is done.
-   *
-   * If the directory cannot be created an exception is thrown.
-   */
-  void createSync({bool recursive: false});
+  /// Synchronously creates the directory if it doesn't exist.
+  ///
+  /// If [recursive] is false, only the last directory in the path is
+  /// created. If [recursive] is true, all non-existing path components
+  /// are created. If the directory already exists nothing is done.
+  ///
+  /// If the directory cannot be created an exception is thrown.
+  void createSync({bool recursive = false});
 
-  /**
-   * Gets the system temp directory.
-   *
-   * Gets the directory provided by the operating system for creating
-   * temporary files and directories in.
-   * The location of the system temp directory is platform-dependent,
-   * and may be set by an environment variable.
-   */
+  /// The system temp directory.
+  ///
+  /// This is the directory provided by the operating system for creating
+  /// temporary files and directories in.
+  /// The location of the system temporary directory is platform-dependent,
+  /// and may be controlled by an environment variable on some platforms.
   static Directory get systemTemp {
     final IOOverrides? overrides = IOOverrides.current;
     if (overrides == null) {
@@ -232,108 +205,104 @@
     return overrides.getSystemTempDirectory();
   }
 
-  /**
-   * Creates a temporary directory in this directory. Additional random
-   * characters are appended to [prefix] to produce a unique directory
-   * name. If [prefix] is missing or null, the empty string is used
-   * for [prefix].
-   *
-   * Returns a [:Future<Directory>:] that completes with the newly
-   * created temporary directory.
-   */
+  /// Creates a temporary directory in this directory.
+  ///
+  /// Additional random characters are appended to [prefix]
+  /// to produce a unique directory name.
+  /// If [prefix] is missing or null, the empty string is used as [prefix].
+  ///
+  /// Returns a `Future<Directory>` that completes with the newly
+  /// created temporary directory.
   Future<Directory> createTemp([String? prefix]);
 
-  /**
-   * Synchronously creates a temporary directory in this directory.
-   * Additional random characters are appended to [prefix] to produce
-   * a unique directory name. If [prefix] is missing or null, the empty
-   * string is used for [prefix].
-   *
-   * Returns the newly created temporary directory.
-   */
+  /// Synchronously creates a temporary directory in this directory.
+  ///
+  /// Additional random characters are appended to [prefix] to produce
+  /// a unique directory name. If [prefix] is missing or null, the empty
+  /// string is used as [prefix].
+  ///
+  /// Returns the newly created temporary directory.
   Directory createTempSync([String? prefix]);
 
   Future<String> resolveSymbolicLinks();
 
   String resolveSymbolicLinksSync();
 
-  /**
-   * Renames this directory. Returns a [:Future<Directory>:] that completes
-   * with a [Directory] instance for the renamed directory.
-   *
-   * If newPath identifies an existing directory, that directory is
-   * replaced. If newPath identifies an existing file, the operation
-   * fails and the future completes with an exception.
-   */
+  /// Renames this directory.
+  ///
+  /// Returns a `Future<Directory>` that completes
+  /// with a [Directory] for the renamed directory.
+  ///
+  /// If [newPath] identifies an existing directory, that directory is
+  /// removed first.
+  /// If [newPath] identifies an existing file, the operation
+  /// fails and the future completes with an exception.
   Future<Directory> rename(String newPath);
 
-  /**
-   * Synchronously renames this directory. Returns a [Directory]
-   * instance for the renamed directory.
-   *
-   * If newPath identifies an existing directory, that directory is
-   * replaced. If newPath identifies an existing file the operation
-   * fails and an exception is thrown.
-   */
+  /// Synchronously renames this directory.
+  ///
+  /// Returns a [Directory] for the renamed directory.
+  ///
+  /// If [newPath] identifies an existing directory, that directory is
+  /// removed first.
+  /// If [newPath] identifies an existing file the operation
+  /// fails and an exception is thrown.
   Directory renameSync(String newPath);
 
-  /**
-   * Returns a [Directory] instance whose path is the absolute path to [this].
-   *
-   * The absolute path is computed by prefixing
-   * a relative path with the current working directory, and returning
-   * an absolute path unchanged.
-   */
+  /// A [Directory] whose path is the absolute path of [this].
+  ///
+  /// The absolute path is computed by prefixing
+  /// a relative path with the current working directory,
+  /// or by returning an absolute path unchanged.
   Directory get absolute;
 
-  /**
-   * Lists the sub-directories and files of this [Directory].
-   * Optionally recurses into sub-directories.
-   *
-   * If [followLinks] is false, then any symbolic links found
-   * are reported as [Link] objects, rather than as directories or files,
-   * and are not recursed into.
-   *
-   * If [followLinks] is true, then working links are reported as
-   * directories or files, depending on
-   * their type, and links to directories are recursed into.
-   * Broken links are reported as [Link] objects.
-   * If a symbolic link makes a loop in the file system, then a recursive
-   * listing will not follow a link twice in the
-   * same recursive descent, but will report it as a [Link]
-   * the second time it is seen.
-   *
-   * The result is a stream of [FileSystemEntity] objects
-   * for the directories, files, and links.
-   */
+  /// Lists the sub-directories and files of this [Directory].
+  ///
+  /// Optionally recurses into sub-directories.
+  ///
+  /// If [followLinks] is `false`, then any symbolic links found
+  /// are reported as [Link] objects, rather than as directories or files,
+  /// and are not recursed into.
+  ///
+  /// If [followLinks] is `true`, then working links are reported as
+  /// directories or files, depending on what they point to,
+  /// and links to directories are recursed into f [recursive] is `true`.
+  ///
+  /// Broken links are reported as [Link] objects.
+  ///
+  /// If a symbolic link makes a loop in the file system, then a recursive
+  /// listing will not follow a link twice in the
+  /// same recursive descent, but will report it as a [Link]
+  /// the second time it is seen.
+  ///
+  /// The result is a stream of [FileSystemEntity] objects
+  /// for the directories, files, and links.
   Stream<FileSystemEntity> list(
-      {bool recursive: false, bool followLinks: true});
+      {bool recursive = false, bool followLinks = true});
 
-  /**
-   * Lists the sub-directories and files of this [Directory].
-   * Optionally recurses into sub-directories.
-   *
-   * If [followLinks] is false, then any symbolic links found
-   * are reported as [Link] objects, rather than as directories or files,
-   * and are not recursed into.
-   *
-   * If [followLinks] is true, then working links are reported as
-   * directories or files, depending on
-   * their type, and links to directories are recursed into.
-   * Broken links are reported as [Link] objects.
-   * If a link makes a loop in the file system, then a recursive
-   * listing will not follow a link twice in the
-   * same recursive descent, but will report it as a [Link]
-   * the second time it is seen.
-   *
-   * Returns a [List] containing [FileSystemEntity] objects for the
-   * directories, files, and links.
-   */
+  /// Lists the sub-directories and files of this [Directory].
+  /// Optionally recurses into sub-directories.
+  ///
+  /// If [followLinks] is `false`, then any symbolic links found
+  /// are reported as [Link] objects, rather than as directories or files,
+  /// and are not recursed into.
+  ///
+  /// If [followLinks] is `true`, then working links are reported as
+  /// directories or files, depending on what they point to,
+  /// and links to directories are recursed into if `recursive` is `true`.
+  ///
+  /// Broken links are reported as [Link] objects.
+  ///
+  /// If a link makes a loop in the file system, then a recursive
+  /// listing will not follow a link twice in the
+  /// same recursive descent, but will report it as a [Link]
+  /// the second time it is seen.
+  ///
+  /// Returns a [List] containing [FileSystemEntity] objects for the
+  /// directories, files, and links.
   List<FileSystemEntity> listSync(
-      {bool recursive: false, bool followLinks: true});
+      {bool recursive = false, bool followLinks = true});
 
-  /**
-   * Returns a human readable string for this Directory instance.
-   */
+  /// Returns a human readable representation of this [Directory].
   String toString();
 }
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index 0a356e1..d3bc43f 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -98,7 +98,7 @@
 
   Directory get absolute => new Directory(_absolutePath);
 
-  Future<Directory> create({bool recursive: false}) {
+  Future<Directory> create({bool recursive = false}) {
     if (recursive) {
       return exists().then((exists) {
         if (exists) return this;
@@ -121,7 +121,7 @@
     }
   }
 
-  void createSync({bool recursive: false}) {
+  void createSync({bool recursive = false}) {
     if (recursive) {
       if (existsSync()) return;
       if (path != parent.path) {
@@ -184,7 +184,7 @@
     return new Directory(result);
   }
 
-  Future<Directory> _delete({bool recursive: false}) {
+  Future<Directory> _delete({bool recursive = false}) {
     return _File._dispatchWithNamespace(
             _IOService.directoryDelete, [null, _rawPath, recursive])
         .then((response) {
@@ -195,7 +195,7 @@
     });
   }
 
-  void _deleteSync({bool recursive: false}) {
+  void _deleteSync({bool recursive = false}) {
     var result = _deleteNative(_Namespace._namespace, _rawPath, recursive);
     if (result is OSError) {
       throw new FileSystemException("Deletion failed", path, result);
@@ -223,7 +223,7 @@
   }
 
   Stream<FileSystemEntity> list(
-      {bool recursive: false, bool followLinks: true}) {
+      {bool recursive = false, bool followLinks = true}) {
     return new _AsyncDirectoryLister(
             // FIXME(bkonyi): here we're using `path` directly, which might cause issues
             // if it is not UTF-8 encoded.
@@ -235,7 +235,7 @@
   }
 
   List<FileSystemEntity> listSync(
-      {bool recursive: false, bool followLinks: true}) {
+      {bool recursive = false, bool followLinks = true}) {
     // TODO(40614): Remove once non-nullability is sound.
     ArgumentError.checkNotNull(recursive, "recursive");
     ArgumentError.checkNotNull(followLinks, "followLinks");
diff --git a/sdk/lib/io/embedder_config.dart b/sdk/lib/io/embedder_config.dart
index 2042aa5..fcac6d1 100644
--- a/sdk/lib/io/embedder_config.dart
+++ b/sdk/lib/io/embedder_config.dart
@@ -4,35 +4,36 @@
 
 part of dart.io;
 
-/// Embedder-specific, fine-grained dart:io configuration.
+/// Embedder-specific, fine-grained `dart:io` configuration.
 ///
 /// This class contains per-Isolate flags that an embedder can set to put
 /// fine-grained limitations on what process-visible operations Isolates are
-/// permitted to use (e.g. exit()). By default, the whole dart:io API is
+/// permitted to use (e.g. [exit]). By default, the whole `dart:io` API is
 /// enabled. When a disallowed operation is attempted, an `UnsupportedError` is
 /// thrown.
 @pragma('vm:entry-point')
 abstract class _EmbedderConfig {
-  /// The Isolate may set Directory.current.
+  /// Whether the isolate may set [Directory.current].
   static bool _mayChdir = true;
 
-  /// The Isolate may call exit().
+  /// Whether the isolate may call [exit].
   @pragma("vm:entry-point")
   static bool _mayExit = true;
 
-  // The Isolate may set Stdin.echoMode.
+  // Whether the isolate may set [Stdin.echoMode].
   @pragma('vm:entry-point')
   static bool _maySetEchoMode = true;
 
-  // The Isolate may set Stdin.lineMode.
+  // Whether the isolate may set [Stdin.lineMode].
   @pragma('vm:entry-point')
   static bool _maySetLineMode = true;
 
-  /// The Isolate may call sleep().
+  /// Whether the isolate may call [sleep].
   @pragma('vm:entry-point')
   static bool _maySleep = true;
 
-  /// The Isolate may establish insecure socket connections to all domains.
+  /// Whether the isolate may establish insecure socket connections
+  /// to all domains.
   ///
   /// This setting can be overridden by per-domain policies.
   @pragma('vm:entry-point')
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index 9c1f2f5..14d68bb 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -4,9 +4,7 @@
 
 part of dart.io;
 
-/**
- * The modes in which a File can be opened.
- */
+/// The modes in which a [File] can be opened.
 class FileMode {
   /// The mode for opening a file only for reading.
   static const read = const FileMode._internal(0);
@@ -97,152 +95,144 @@
   const FileLock._internal(this._type);
 }
 
-/**
- * A reference to a file on the file system.
- *
- * A File instance is an object that holds a [path] on which operations can
- * be performed.
- * You can get the parent directory of the file using the getter [parent],
- * a property inherited from [FileSystemEntity].
- *
- * Create a new File object with a pathname to access the specified file on the
- * file system from your program.
- *
- *     var myFile = new File('file.txt');
- *
- * The File class contains methods for manipulating files and their contents.
- * Using methods in this class, you can open and close files, read to and write
- * from them, create and delete them, and check for their existence.
- *
- * When reading or writing a file, you can use streams (with [openRead]),
- * random access operations (with [open]),
- * or convenience methods such as [readAsString],
- *
- * Most methods in this class occur in synchronous and asynchronous pairs,
- * for example, [readAsString] and [readAsStringSync].
- * Unless you have a specific reason for using the synchronous version
- * of a method, prefer the asynchronous version to avoid blocking your program.
- *
- * ## If path is a link
- *
- * If [path] is a symbolic link, rather than a file,
- * then the methods of File operate on the ultimate target of the
- * link, except for [delete] and [deleteSync], which operate on
- * the link.
- *
- * ## Read from a file
- *
- * The following code sample reads the entire contents from a file as a string
- * using the asynchronous [readAsString] method:
- *
- *     import 'dart:async';
- *     import 'dart:io';
- *
- *     void main() {
- *       new File('file.txt').readAsString().then((String contents) {
- *         print(contents);
- *       });
- *     }
- *
- * A more flexible and useful way to read a file is with a [Stream].
- * Open the file with [openRead], which returns a stream that
- * provides the data in the file as chunks of bytes.
- * Listen to the stream for data and process as needed.
- * You can use various transformers in succession to manipulate the
- * data into the required format or to prepare it for output.
- *
- * You might want to use a stream to read large files,
- * to manipulate the data with transformers,
- * or for compatibility with another API, such as [WebSocket]s.
- *
- *     import 'dart:io';
- *     import 'dart:convert';
- *     import 'dart:async';
- *
- *     main() {
- *       final file = new File('file.txt');
- *       Stream<List<int>> inputStream = file.openRead();
- *
- *       inputStream
- *         .transform(utf8.decoder)       // Decode bytes to UTF-8.
- *         .transform(new LineSplitter()) // Convert stream to individual lines.
- *         .listen((String line) {        // Process results.
- *             print('$line: ${line.length} bytes');
- *           },
- *           onDone: () { print('File is now closed.'); },
- *           onError: (e) { print(e.toString()); });
- *     }
- *
- * ## Write to a file
- *
- * To write a string to a file, use the [writeAsString] method:
- *
- *     import 'dart:io';
- *
- *     void main() {
- *       final filename = 'file.txt';
- *       new File(filename).writeAsString('some content')
- *         .then((File file) {
- *           // Do something with the file.
- *         });
- *     }
- *
- * You can also write to a file using a [Stream]. Open the file with
- * [openWrite], which returns an [IOSink] to which you can write data.
- * Be sure to close the sink with the [IOSink.close] method.
- *
- *     import 'dart:io';
- *
- *     void main() {
- *       var file = new File('file.txt');
- *       var sink = file.openWrite();
- *       sink.write('FILE ACCESSED ${new DateTime.now()}\n');
- *
- *       // Close the IOSink to free system resources.
- *       sink.close();
- *     }
- *
- * ## The use of Futures
- *
- * To avoid unintentional blocking of the program,
- * several methods use a [Future] to return a value. For example,
- * the [length] method, which gets the length of a file, returns a Future.
- * Use `then` to register a callback function, which is called when
- * the value is ready.
- *
- *     import 'dart:io';
- *
- *     main() {
- *       final file = new File('file.txt');
- *
- *       file.length().then((len) {
- *         print(len);
- *       });
- *     }
- *
- * In addition to length, the [exists], [lastModified], [stat], and
- * other methods, return Futures.
- *
- * ## Other resources
- *
- * * The [Files and directories](https://dart.dev/guides/libraries/library-tour#files-and-directories)
- *   section of the library tour.
- *
- * * [Write Command-Line Apps](https://dart.dev/tutorials/server/cmdline),
- *   a tutorial about writing command-line apps, includes information about
- *   files and directories.
- */
+/// A reference to a file on the file system.
+///
+/// A `File` holds a [path] on which operations can be performed.
+/// You can get the parent directory of the file using [parent],
+/// a property inherited from [FileSystemEntity].
+///
+/// Create a new `File` object with a pathname to access the specified file on the
+/// file system from your program.
+/// ```dart
+/// var myFile = File('file.txt');
+/// ```
+/// The `File` class contains methods for manipulating files and their contents.
+/// Using methods in this class, you can open and close files, read to and write
+/// from them, create and delete them, and check for their existence.
+///
+/// When reading or writing a file, you can use streams (with [openRead]),
+/// random access operations (with [open]),
+/// or convenience methods such as [readAsString],
+///
+/// Most methods in this class occur in synchronous and asynchronous pairs,
+/// for example, [readAsString] and [readAsStringSync].
+/// Unless you have a specific reason for using the synchronous version
+/// of a method, prefer the asynchronous version to avoid blocking your program.
+///
+/// ## If path is a link
+///
+/// If [path] is a symbolic link, rather than a file,
+/// then the methods of `File` operate on the ultimate target of the
+/// link, except for [delete] and [deleteSync], which operate on
+/// the link.
+///
+/// ## Read from a file
+///
+/// The following code sample reads the entire contents from a file as a string
+/// using the asynchronous [readAsString] method:
+/// ```dart
+/// import 'dart:async';
+/// import 'dart:io';
+///
+/// void main() {
+///   File('file.txt').readAsString().then((String contents) {
+///     print(contents);
+///   });
+/// }
+/// ```
+/// A more flexible and useful way to read a file is with a [Stream].
+/// Open the file with [openRead], which returns a stream that
+/// provides the data in the file as chunks of bytes.
+/// Read the stream to process the file contents when available.
+/// You can use various transformers in succession to manipulate the
+/// file content into the required format, or to prepare it for output.
+///
+/// You might want to use a stream to read large files,
+/// to manipulate the data with transformers,
+/// or for compatibility with another API, such as [WebSocket]s.
+/// ```dart
+/// import 'dart:io';
+/// import 'dart:convert';
+/// import 'dart:async';
+///
+/// void main() async {
+///   final file = File('file.txt');
+///   Stream<String> lines = file.openRead()
+///     .transform(utf8.decoder)       // Decode bytes to UTF-8.
+///     .transform(LineSplitter());    // Convert stream to individual lines.
+///   try {
+///     await for (var line in lines) {
+///       print('$line: ${line.length} characters');
+///     }
+///     print('File is now closed.');
+///   } catch (e) {
+///     print('Error: $e');
+///   }
+/// }
+/// ```
+/// ## Write to a file
+///
+/// To write a string to a file, use the [writeAsString] method:
+/// ```dart
+/// import 'dart:io';
+///
+/// void main() async {
+///   final filename = 'file.txt';
+///   var file = await File(filename).writeAsString('some content');
+///   // Do something with the file.
+/// }
+/// ```
+/// You can also write to a file using a [Stream]. Open the file with
+/// [openWrite], which returns an [IOSink] to which you can write data.
+/// Be sure to close the sink with the [IOSink.close] method.
+/// ```dart
+/// import 'dart:io';
+///
+/// void main() {
+///   var file = File('file.txt');
+///   var sink = file.openWrite();
+///   sink.write('FILE ACCESSED ${DateTime.now()}\n');
+///
+///   // Close the IOSink to free system resources.
+///   sink.close();
+/// }
+/// ```
+/// ## The use of asynchronous methods
+///
+/// To avoid unintentional blocking of the program,
+/// several methods are asynchronous and return a [Future]. For example,
+/// the [length] method, which gets the length of a file, returns a [Future].
+/// Wait for the future to get the result when it's ready.
+/// ```dart
+/// import 'dart:io';
+///
+/// void main() async {
+///   final file = File('file.txt');
+///
+///   var length = await file.length();
+///   print(length);
+/// }
+/// ```
+/// In addition to length, the [exists], [lastModified], [stat], and
+/// other methods, are asynchronous.
+///
+/// ## Other resources
+///
+/// * The [Files and directories](https://dart.dev/guides/libraries/library-tour#files-and-directories)
+///   section of the library tour.
+///
+/// * [Write Command-Line Apps](https://dart.dev/tutorials/server/cmdline),
+///   a tutorial about writing command-line apps, includes information about
+///   files and directories.
 @pragma("vm:entry-point")
 abstract class File implements FileSystemEntity {
-  /**
-   * Creates a [File] object.
-   *
-   * If [path] is a relative path, it will be interpreted relative to the
-   * current working directory (see [Directory.current]), when used.
-   *
-   * If [path] is an absolute path, it will be immune to changes to the
-   * current working directory.
-   */
+  /// Creates a [File] object.
+  ///
+  /// If [path] is a relative path, it will be interpreted relative to the
+  /// current working directory (see [Directory.current]), when used.
+  ///
+  /// If [path] is an absolute path, it will be immune to changes to the
+  /// current working directory.
   @pragma("vm:entry-point")
   factory File(String path) {
     final IOOverrides? overrides = IOOverrides.current;
@@ -252,733 +242,686 @@
     return overrides.createFile(path);
   }
 
-  /**
-   * Create a File object from a URI.
-   *
-   * If [uri] cannot reference a file this throws [UnsupportedError].
-   */
+  /// Create a [File] object from a URI.
+  ///
+  /// If [uri] cannot reference a file this throws [UnsupportedError].
   factory File.fromUri(Uri uri) => new File(uri.toFilePath());
 
-  /**
-   * Creates a File object from a raw path, that is, a sequence of bytes
-   * as represented by the OS.
-   */
+  /// Creates a [File] object from a raw path.
+  ///
+  /// A raw path is a sequence of bytes, as paths are represented by the OS.
   @pragma("vm:entry-point")
   factory File.fromRawPath(Uint8List rawPath) {
     // TODO(bkonyi): Handle overrides.
     return new _File.fromRawPath(rawPath);
   }
 
-  /**
-   * Create the file. Returns a `Future<File>` that completes with
-   * the file when it has been created.
-   *
-   * If [recursive] is false, the default, the file is created only if
-   * all directories in the path exist. If [recursive] is true, all
-   * non-existing path components are created.
-   *
-   * Existing files are left untouched by [create]. Calling [create] on an
-   * existing file might fail if there are restrictive permissions on
-   * the file.
-   *
-   * Completes the future with a [FileSystemException] if the operation fails.
-   */
-  Future<File> create({bool recursive: false});
+  /// Creates the file.
+  ///
+  /// Returns a `Future<File>` that completes with
+  /// the file when it has been created.
+  ///
+  /// If [recursive] is `false`, the default, the file is created only if
+  /// all directories in its path alredy exist. If [recursive] is `true`, any
+  /// non-existing parent paths are created first.
+  ///
+  /// Existing files are left untouched by [create]. Calling [create] on an
+  /// existing file might fail if there are restrictive permissions on
+  /// the file.
+  ///
+  /// Completes the future with a [FileSystemException] if the operation fails.
+  Future<File> create({bool recursive = false});
 
-  /**
-   * Synchronously create the file. Existing files are left untouched
-   * by [createSync]. Calling [createSync] on an existing file might fail
-   * if there are restrictive permissions on the file.
-   *
-   * If [recursive] is false, the default, the file is created
-   * only if all directories in the path exist.
-   * If [recursive] is true, all non-existing path components are created.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
-  void createSync({bool recursive: false});
+  /// Synchronously creates the file.
+  ///
+  /// Existing files are left untouched by [createSync].
+  /// Calling [createSync] on an existing file might fail
+  /// if there are restrictive permissions on the file.
+  ///
+  /// If [recursive] is `false`, the default, the file is created
+  /// only if all directories in its path already exist.
+  /// If [recursive] is `true`, all non-existing parent paths are created first.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
+  void createSync({bool recursive = false});
 
-  /**
-   * Renames this file. Returns a `Future<File>` that completes
-   * with a [File] instance for the renamed file.
-   *
-   * If [newPath] identifies an existing file, that file is
-   * replaced. If [newPath] identifies an existing directory, the
-   * operation fails and the future completes with an exception.
-   */
+  /// Renames this file.
+  ///
+  /// Returns a `Future<File>` that completes
+  /// with a [File] for the renamed file.
+  ///
+  /// If [newPath] is a relative path, it is resolved against
+  /// the current working directory ([Directory.cwd]).
+  /// This means that simply changing the name of a file,
+  /// but keeping it the original directory,
+  /// requires creating a new complete path with the new name
+  /// at the end. Example:
+  /// ```dart
+  /// Future<File> changeFileNameOnly(File file, String newFileName) {
+  ///   var path = file.path;
+  ///   var lastSeparator = path.lastIndexOf(Platform.pathSeparator);
+  ///   var newPath = path.substring(0, lastSeparator + 1) + newFileName;
+  ///   return file.rename(newPath);
+  /// }
+  /// ```
+  /// On some platforms, a rename operation cannot move a file between
+  /// different file systems. If that is the case, instead [copy] the
+  /// file to the new location and then [remove] the original.
+  ///
+  /// If [newPath] identifies an existing file, that file is
+  /// removed first. If [newPath] identifies an existing directory, the
+  /// operation fails and the future completes with an exception.
   Future<File> rename(String newPath);
 
-  /**
-   * Synchronously renames this file. Returns a [File]
-   * instance for the renamed file.
-   *
-   * If [newPath] identifies an existing file, that file is
-   * replaced. If [newPath] identifies an existing directory the
-   * operation fails and an exception is thrown.
-   */
+  /// Synchronously renames this file.
+  ///
+  /// Returns a [File] for the renamed file.
+  ///
+  /// If [newPath] is a relative path, it is resolved against
+  /// the current working directory ([Directory.cwd]).
+  /// This means that simply changing the name of a file,
+  /// but keeping it the original directory,
+  /// requires creating a new complete path with the new name
+  /// at the end. Example:
+  /// ```dart
+  /// File changeFileNameOnlySync(File file, String newFileName) {
+  ///   var path = file.path;
+  ///   var lastSeparator = path.lastIndexOf(Platform.pathSeparator);
+  ///   var newPath = path.substring(0, lastSeparator + 1) + newFileName;
+  ///   return file.renameSync(newPath);
+  /// }
+  /// ```
+  /// On some platforms, a rename operation cannot move a file between
+  /// different file systems. If that is the case, instead [copySync] the
+  /// file to the new location and then [removeSync] the original.
+  ///
+  /// If [newPath] identifies an existing file, that file is
+  /// removed first. If [newPath] identifies an existing directory the
+  /// operation fails and an exception is thrown.
   File renameSync(String newPath);
 
-  /**
-   * Copy this file. Returns a `Future<File>` that completes
-   * with a [File] instance for the copied file.
-   *
-   * If [newPath] identifies an existing file, that file is
-   * replaced. If [newPath] identifies an existing directory, the
-   * operation fails and the future completes with an exception.
-   */
+  /// Copies this file.
+  ///
+  /// If [newPath] is a relative path, it is resolved against
+  /// the current working directory ([Directory.cwd]).
+  ///
+  /// Returns a `Future<File>` that completes
+  /// with a [File] for the copied file.
+  ///
+  /// If [newPath] identifies an existing file, that file is
+  /// removed first. If [newPath] identifies an existing directory, the
+  /// operation fails and the future completes with an exception.
   Future<File> copy(String newPath);
 
-  /**
-   * Synchronously copy this file. Returns a [File]
-   * instance for the copied file.
-   *
-   * If [newPath] identifies an existing file, that file is
-   * replaced. If [newPath] identifies an existing directory the
-   * operation fails and an exception is thrown.
-   */
+  /// Synchronously copies this file.
+  ///
+  /// If [newPath] is a relative path, it is resolved against
+  /// the current working directory ([Directory.cwd]).
+  ///
+  /// Returns a [File] for the copied file.
+  ///
+  /// If [newPath] identifies an existing file, that file is
+  /// removed first. If [newPath] identifies an existing directory the
+  /// operation fails and an exception is thrown.
   File copySync(String newPath);
 
-  /**
-   * Get the length of the file. Returns a `Future<int>` that
-   * completes with the length in bytes.
-   */
+  /// The length of the file.
+  ///
+  /// Returns a `Future<int>` that completes with the length in bytes.
   Future<int> length();
 
-  /**
-   * Synchronously get the length of the file.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// The length of the file provided synchronously.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   int lengthSync();
 
-  /**
-   * Returns a [File] instance whose path is the absolute path to [this].
-   *
-   * The absolute path is computed by prefixing
-   * a relative path with the current working directory, and returning
-   * an absolute path unchanged.
-   */
+  /// A [File] with the absolute path of [path].
+  ///
+  /// The absolute path is computed by prefixing
+  /// a relative path with the current working directory,
+  /// or returning an absolute path unchanged.
   File get absolute;
 
-/**
- * Get the last-accessed time of the file.
- *
- * Returns a `Future<DateTime>` that completes with the date and time when the
- * file was last accessed, if the information is available.
- *
- * Throws a [FileSystemException] if the operation fails.
- */
+  /// The last-accessed time of the file.
+  ///
+  /// Returns a `Future<DateTime>` that completes with the date and time when the
+  /// file was last accessed, if the information is available.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   Future<DateTime> lastAccessed();
 
-/**
- * Get the last-accessed time of the file.
- *
- * Returns the date and time when the file was last accessed,
- * if the information is available. Blocks until the information can be returned
- * or it is determined that the information is not available.
- *
- * Throws a [FileSystemException] if the operation fails.
- */
+  /// The last-accessed time of the file.
+  ///
+  /// Returns the date and time when the file was last accessed,
+  /// if the information is available. Blocks until the information can be returned
+  /// or it is determined that the information is not available.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   DateTime lastAccessedSync();
 
-  /**
-   * Modifies the time the file was last accessed.
-   *
-   * Returns a [Future] that completes once the operation has completed.
-   *
-   * Throws a [FileSystemException] if the time cannot be set.
-   */
+  /// Modifies the time the file was last accessed.
+  ///
+  /// Returns a [Future] that completes once the operation has completed.
+  ///
+  /// Throws a [FileSystemException] if the time cannot be set.
   Future setLastAccessed(DateTime time);
 
-  /**
-   * Synchronously modifies the time the file was last accessed.
-   *
-   * Throws a [FileSystemException] if the time cannot be set.
-   */
+  /// Synchronously modifies the time the file was last accessed.
+  ///
+  /// Throws a [FileSystemException] if the time cannot be set.
   void setLastAccessedSync(DateTime time);
 
-/**
- * Get the last-modified time of the file.
- *
- * Returns a `Future<DateTime>` that completes with the date and time when the
- * file was last modified, if the information is available.
- *
- * Throws a [FileSystemException] if the operation fails.
- */
+  /// Get the last-modified time of the file.
+  ///
+  /// Returns a `Future<DateTime>` that completes with the date and time when the
+  /// file was last modified, if the information is available.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   Future<DateTime> lastModified();
 
-/**
- * Get the last-modified time of the file.
- *
- * Returns the date and time when the file was last modified,
- * if the information is available. Blocks until the information can be returned
- * or it is determined that the information is not available.
- *
- * Throws a [FileSystemException] if the operation fails.
- */
+  /// Get the last-modified time of the file.
+  ///
+  /// Returns the date and time when the file was last modified,
+  /// if the information is available. Blocks until the information can be returned
+  /// or it is determined that the information is not available.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   DateTime lastModifiedSync();
 
-  /**
-   * Modifies the time the file was last modified.
-   *
-   * Returns a [Future] that completes once the operation has completed.
-   *
-   * Throws a [FileSystemException] if the time cannot be set.
-   */
+  /// Modifies the time the file was last modified.
+  ///
+  /// Returns a [Future] that completes once the operation has completed.
+  ///
+  /// Throws a [FileSystemException] if the time cannot be set.
   Future setLastModified(DateTime time);
 
-  /**
-   * Synchronously modifies the time the file was last modified.
-   *
-   * If the attributes cannot be set, throws a [FileSystemException].
-   */
+  /// Synchronously modifies the time the file was last modified.
+  ///
+  /// If the attributes cannot be set, throws a [FileSystemException].
   void setLastModifiedSync(DateTime time);
 
-  /**
-   * Open the file for random access operations. Returns a
-   * `Future<RandomAccessFile>` that completes with the opened
-   * random access file. [RandomAccessFile]s must be closed using the
-   * [RandomAccessFile.close] method.
-   *
-   * Files can be opened in three modes:
-   *
-   * [FileMode.read]: open the file for reading.
-   *
-   * [FileMode.write]: open the file for both reading and writing and
-   * truncate the file to length zero. If the file does not exist the
-   * file is created.
-   *
-   * [FileMode.append]: same as [FileMode.write] except that the file is
-   * not truncated.
-   */
-  Future<RandomAccessFile> open({FileMode mode: FileMode.read});
+  /// Opens the file for random access operations.
+  ///
+  /// Returns a `Future<RandomAccessFile>` that completes with the opened
+  /// random access file. [RandomAccessFile]s must be closed using the
+  /// [RandomAccessFile.close] method.
+  ///
+  /// Files can be opened in three modes:
+  ///
+  /// * [FileMode.read]: open the file for reading.
+  ///
+  /// * [FileMode.write]: open the file for both reading and writing and
+  /// truncate the file to length zero. If the file does not exist the
+  /// file is created.
+  ///
+  /// * [FileMode.append]: same as [FileMode.write] except that the file is
+  /// not truncated.
+  Future<RandomAccessFile> open({FileMode mode = FileMode.read});
 
-  /**
-   * Synchronously open the file for random access operations. The
-   * result is a [RandomAccessFile] on which random access operations
-   * can be performed. Opened [RandomAccessFile]s must be closed using
-   * the [RandomAccessFile.close] method.
-   *
-   * See [open] for information on the [mode] argument.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
-  RandomAccessFile openSync({FileMode mode: FileMode.read});
+  /// Synchronously opens the file for random access operations.
+  ///
+  /// The result is a [RandomAccessFile] on which random access operations
+  /// can be performed. Opened [RandomAccessFile]s must be closed using
+  /// the [RandomAccessFile.close] method.
+  ///
+  /// See [open] for information on the [mode] argument.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
+  RandomAccessFile openSync({FileMode mode = FileMode.read});
 
-  /**
-   * Create a new independent [Stream] for the contents of this file.
-   *
-   * If [start] is present, the file will be read from byte-offset [start].
-   * Otherwise from the beginning (index 0).
-   *
-   * If [end] is present, only up to byte-index [end] will be read. Otherwise,
-   * until end of file.
-   *
-   * In order to make sure that system resources are freed, the stream
-   * must be read to completion or the subscription on the stream must
-   * be cancelled.
-   */
+  /// Creates a new independent [Stream] for the contents of this file.
+  ///
+  /// If [start] is present, the file will be read from byte-offset [start].
+  /// Otherwise from the beginning (index 0).
+  ///
+  /// If [end] is present, only bytes up to byte-index [end] will be read.
+  /// Otherwise, until end of file.
+  ///
+  /// In order to make sure that system resources are freed, the stream
+  /// must be read to completion or the subscription on the stream must
+  /// be cancelled.
   Stream<List<int>> openRead([int? start, int? end]);
 
-  /**
-   * Creates a new independent [IOSink] for the file. The
-   * [IOSink] must be closed when no longer used, to free
-   * system resources.
-   *
-   * An [IOSink] for a file can be opened in two modes:
-   *
-   * * [FileMode.write]: truncates the file to length zero.
-   * * [FileMode.append]: sets the initial write position to the end
-   *   of the file.
-   *
-   *  When writing strings through the returned [IOSink] the encoding
-   *  specified using [encoding] will be used. The returned [IOSink]
-   *  has an `encoding` property which can be changed after the
-   *  [IOSink] has been created.
-   */
-  IOSink openWrite({FileMode mode: FileMode.write, Encoding encoding: utf8});
+  /// Creates a new independent [IOSink] for the file.
+  ///
+  /// The [IOSink] must be closed when no longer used, to free
+  /// system resources.
+  ///
+  /// An [IOSink] for a file can be opened in two modes:
+  ///
+  /// * [FileMode.write]: truncates the file to length zero.
+  /// * [FileMode.append]: sets the initial write position to the end
+  ///   of the file.
+  ///
+  ///  When writing strings through the returned [IOSink] the encoding
+  ///  specified using [encoding] will be used. The returned [IOSink]
+  ///  has an `encoding` property which can be changed after the
+  ///  [IOSink] has been created.
+  IOSink openWrite({FileMode mode = FileMode.write, Encoding encoding = utf8});
 
-  /**
-   * Read the entire file contents as a list of bytes. Returns a
-   * `Future<Uint8List>` that completes with the list of bytes that
-   * is the contents of the file.
-   */
+  /// Reads the entire file contents as a list of bytes.
+  ///
+  /// Returns a `Future<Uint8List>` that completes with the list of bytes that
+  /// is the contents of the file.
   Future<Uint8List> readAsBytes();
 
-  /**
-   * Synchronously read the entire file contents as a list of bytes.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously reads the entire file contents as a list of bytes.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   Uint8List readAsBytesSync();
 
-  /**
-   * Read the entire file contents as a string using the given
-   * [Encoding].
-   *
-   * Returns a `Future<String>` that completes with the string once
-   * the file contents has been read.
-   */
-  Future<String> readAsString({Encoding encoding: utf8});
+  /// Reads the entire file contents as a string using the given
+  /// [Encoding].
+  ///
+  /// Returns a `Future<String>` that completes with the string once
+  /// the file contents has been read.
+  Future<String> readAsString({Encoding encoding = utf8});
 
-  /**
-   * Synchronously read the entire file contents as a string using the
-   * given [Encoding].
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
-  String readAsStringSync({Encoding encoding: utf8});
+  /// Synchronously reads the entire file contents as a string using the
+  /// given [Encoding].
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
+  String readAsStringSync({Encoding encoding = utf8});
 
-  /**
-   * Read the entire file contents as lines of text using the given
-   * [Encoding].
-   *
-   * Returns a `Future<List<String>>` that completes with the lines
-   * once the file contents has been read.
-   */
-  Future<List<String>> readAsLines({Encoding encoding: utf8});
+  /// Reads the entire file contents as lines of text using the given
+  /// [Encoding].
+  ///
+  /// Returns a `Future<List<String>>` that completes with the lines
+  /// once the file contents has been read.
+  Future<List<String>> readAsLines({Encoding encoding = utf8});
 
-  /**
-   * Synchronously read the entire file contents as lines of text
-   * using the given [Encoding].
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
-  List<String> readAsLinesSync({Encoding encoding: utf8});
+  /// Synchronously reads the entire file contents as lines of text
+  /// using the given [Encoding].
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
+  List<String> readAsLinesSync({Encoding encoding = utf8});
 
-  /**
-   * Write a list of bytes to a file.
-   *
-   * Opens the file, writes the list of bytes to it, and closes the file.
-   * Returns a `Future<File>` that completes with this [File] object once
-   * the entire operation has completed.
-   *
-   * By default [writeAsBytes] creates the file for writing and truncates the
-   * file if it already exists. In order to append the bytes to an existing
-   * file, pass [FileMode.append] as the optional mode parameter.
-   *
-   * If the argument [flush] is set to `true`, the data written will be
-   * flushed to the file system before the returned future completes.
-   */
+  /// Writes a list of bytes to a file.
+  ///
+  /// Opens the file, writes the list of bytes to it, and closes the file.
+  /// Returns a `Future<File>` that completes with this [File] object once
+  /// the entire operation has completed.
+  ///
+  /// By default [writeAsBytes] creates the file for writing and truncates the
+  /// file if it already exists. In order to append the bytes to an existing
+  /// file, pass [FileMode.append] as the optional mode parameter.
+  ///
+  /// If the argument [flush] is set to `true`, the data written will be
+  /// flushed to the file system before the returned future completes.
   Future<File> writeAsBytes(List<int> bytes,
-      {FileMode mode: FileMode.write, bool flush: false});
+      {FileMode mode = FileMode.write, bool flush = false});
 
-  /**
-   * Synchronously write a list of bytes to a file.
-   *
-   * Opens the file, writes the list of bytes to it and closes the file.
-   *
-   * By default [writeAsBytesSync] creates the file for writing and truncates
-   * the file if it already exists. In order to append the bytes to an existing
-   * file, pass [FileMode.append] as the optional mode parameter.
-   *
-   * If the [flush] argument is set to `true` data written will be
-   * flushed to the file system before returning.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously writes a list of bytes to a file.
+  ///
+  /// Opens the file, writes the list of bytes to it and closes the file.
+  ///
+  /// By default [writeAsBytesSync] creates the file for writing and truncates
+  /// the file if it already exists. In order to append the bytes to an existing
+  /// file, pass [FileMode.append] as the optional mode parameter.
+  ///
+  /// If the [flush] argument is set to `true` data written will be
+  /// flushed to the file system before returning.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   void writeAsBytesSync(List<int> bytes,
-      {FileMode mode: FileMode.write, bool flush: false});
+      {FileMode mode = FileMode.write, bool flush = false});
 
-  /**
-   * Write a string to a file.
-   *
-   * Opens the file, writes the string in the given encoding, and closes the
-   * file. Returns a `Future<File>` that completes with this [File] object
-   * once the entire operation has completed.
-   *
-   * By default [writeAsString] creates the file for writing and truncates the
-   * file if it already exists. In order to append the bytes to an existing
-   * file, pass [FileMode.append] as the optional mode parameter.
-   *
-   * If the argument [flush] is set to `true`, the data written will be
-   * flushed to the file system before the returned future completes.
-   *
-   */
+  /// Writes a string to a file.
+  ///
+  /// Opens the file, writes the string in the given encoding, and closes the
+  /// file. Returns a `Future<File>` that completes with this [File] object
+  /// once the entire operation has completed.
+  ///
+  /// By default [writeAsString] creates the file for writing and truncates the
+  /// file if it already exists. In order to append the bytes to an existing
+  /// file, pass [FileMode.append] as the optional mode parameter.
+  ///
+  /// If the argument [flush] is set to `true`, the data written will be
+  /// flushed to the file system before the returned future completes.
+  ///
   Future<File> writeAsString(String contents,
-      {FileMode mode: FileMode.write,
-      Encoding encoding: utf8,
-      bool flush: false});
+      {FileMode mode = FileMode.write,
+      Encoding encoding = utf8,
+      bool flush = false});
 
-  /**
-   * Synchronously write a string to a file.
-   *
-   * Opens the file, writes the string in the given encoding, and closes the
-   * file.
-   *
-   * By default [writeAsStringSync] creates the file for writing and
-   * truncates the file if it already exists. In order to append the bytes
-   * to an existing file, pass [FileMode.append] as the optional mode
-   * parameter.
-   *
-   * If the [flush] argument is set to `true` data written will be
-   * flushed to the file system before returning.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously writes a string to a file.
+  ///
+  /// Opens the file, writes the string in the given encoding, and closes the
+  /// file.
+  ///
+  /// By default [writeAsStringSync] creates the file for writing and
+  /// truncates the file if it already exists. In order to append the bytes
+  /// to an existing file, pass [FileMode.append] as the optional mode
+  /// parameter.
+  ///
+  /// If the [flush] argument is set to `true` data written will be
+  /// flushed to the file system before returning.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   void writeAsStringSync(String contents,
-      {FileMode mode: FileMode.write,
-      Encoding encoding: utf8,
-      bool flush: false});
+      {FileMode mode = FileMode.write,
+      Encoding encoding = utf8,
+      bool flush = false});
 
-  /**
-   * Get the path of the file.
-   */
+  /// Get the path of the file.
   String get path;
 }
 
-/**
- * `RandomAccessFile` provides random access to the data in a
- * file.
- *
- * `RandomAccessFile` objects are obtained by calling the
- * `open` method on a [File] object.
- *
- * A `RandomAccessFile` have both asynchronous and synchronous
- * methods. The asynchronous methods all return a `Future`
- * whereas the synchronous methods will return the result directly,
- * and block the current isolate until the result is ready.
- *
- * At most one asynchronous method can be pending on a given `RandomAccessFile`
- * instance at the time. If an asynchronous method is called when one is
- * already in progress a [FileSystemException] is thrown.
- *
- * If an asynchronous method is pending it is also not possible to call any
- * synchronous methods. This will also throw a [FileSystemException].
- */
+/// Random access to the data in a file.
+///
+/// `RandomAccessFile` objects are obtained by calling the
+/// `open` method on a [File] object.
+///
+/// A `RandomAccessFile` has both asynchronous and synchronous
+/// methods. The asynchronous methods all return a [Future]
+/// whereas the synchronous methods will return the result directly,
+/// and block the current isolate until the result is ready.
+///
+/// At most one asynchronous method can be pending on a given `RandomAccessFile`
+/// instance at the time. If another asynchronous method is called when one is
+/// already in progress, a [FileSystemException] is thrown.
+///
+/// If an asynchronous method is pending, it is also not possible to call any
+/// synchronous methods. This will also throw a [FileSystemException].
 abstract class RandomAccessFile {
-  /**
-   * Closes the file. Returns a `Future` that
-   * completes when it has been closed.
-   */
+  /// Closes the file.
+  ///
+  /// Returns a [Future] that completes when it has been closed.
   Future<void> close();
 
-  /**
-   * Synchronously closes the file.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously closes the file.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   void closeSync();
 
-  /**
-   * Reads a byte from the file. Returns a `Future<int>` that
-   * completes with the byte, or with -1 if end-of-file has been reached.
-   */
+  /// Reads a byte from the file.
+  ///
+  /// Returns a `Future<int>` that completes with the byte,
+  /// or with -1 if end-of-file has been reached.
   Future<int> readByte();
 
-  /**
-   * Synchronously reads a single byte from the file. If end-of-file
-   * has been reached -1 is returned.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously reads a single byte from the file.
+  ///
+  /// If end-of-file has been reached -1 is returned.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   int readByteSync();
 
-  /**
-   * Reads [bytes] bytes from a file and returns the result as a list of bytes.
-   */
-  Future<Uint8List> read(int bytes);
+  /// Reads up to [count] bytes from a file.
+  Future<Uint8List> read(int count);
 
-  /**
-   * Synchronously reads a maximum of [bytes] bytes from a file and
-   * returns the result in a list of bytes.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
-  Uint8List readSync(int bytes);
+  /// Synchronously reads up to [count] bytes from a file
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
+  Uint8List readSync(int count);
 
-  /**
-   * Reads into an existing [List<int>] from the file. If [start] is present,
-   * the bytes will be filled into [buffer] from at index [start], otherwise
-   * index 0. If [end] is present, the [end] - [start] bytes will be read into
-   * [buffer], otherwise up to [buffer.length]. If [end] == [start] nothing
-   * happens.
-   *
-   * Returns a `Future<int>` that completes with the number of bytes read.
-   */
+  /// Reads bytes into an existing [buffer].
+  ///
+  /// Reads bytes and writes then into the the range of [buffer]
+  /// from [start] to [end].
+  /// The [start] must be non-negative and no greater than `buffer.length`.
+  /// If [end] is omitted, it defaults to [buffer.length].
+  /// Otherwise [end] must be no less than [start]
+  /// and no greater than `buffer.length`.
+  ///
+  /// Returns the number of bytes read. This maybe be less than `end - start`
+  /// if the file doesn't have that many bytes to read.
   Future<int> readInto(List<int> buffer, [int start = 0, int? end]);
 
-  /**
-   * Synchronously reads into an existing [List<int>] from the file and returns
-   * the number of bytes read.
-   *
-   * If [start] is present, the bytes will be filled into [buffer] from at
-   * index [start], otherwise index 0.  If [end] is present, the
-   * [end] - [start] bytes will be read into [buffer], otherwise up to
-   * [buffer.length]. If [end] == [start] nothing happens.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously reads into an existing [buffer].
+  ///
+  /// Reads bytes and writes then into the the range of [buffer]
+  /// from [start] to [end].
+  /// The [start] must be non-negative and no greater than `buffer.length`.
+  /// If [end] is omitted, it defaults to [buffer.length].
+  /// Otherwise [end] must be no less than [start]
+  /// and no greater than `buffer.length`.
+  ///
+  /// Returns the number of bytes read. This maybe be less than `end - start`
+  /// if the file doesn't have that many bytes to read.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   int readIntoSync(List<int> buffer, [int start = 0, int? end]);
 
-  /**
-   * Writes a single byte to the file. Returns a
-   * `Future<RandomAccessFile>` that completes with this
-   * RandomAccessFile when the write completes.
-   */
+  /// Writes a single byte to the file.
+  ///
+  /// Returns a `Future<RandomAccessFile>` that completes with this
+  /// random access file when the write completes.
   Future<RandomAccessFile> writeByte(int value);
 
-  /**
-   * Synchronously writes a single byte to the file. Returns 1 on success.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously writes a single byte to the file.
+  ///
+  /// Returns 1 on success.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   int writeByteSync(int value);
 
-  /**
-   * Writes from a [List<int>] to the file. It will read the buffer from index
-   * [start] to index [end]. If [start] is omitted, it'll start from index 0.
-   * If [end] is omitted, it will write to end of [buffer].
-   *
-   * Returns a `Future<RandomAccessFile>` that completes with this
-   * [RandomAccessFile] when the write completes.
-   */
+  /// Writes from a [buffer] to the file.
+  ///
+  /// Will read the buffer from index [start] to index [end].
+  /// The [start] must be non-negative and no greater than `buffer.length`.
+  /// If [end] is omitted, it defaults to [buffer.length].
+  /// Otherwise [end] must be no less than [start]
+  /// and no greater than `buffer.length`.
+  ///
+  /// Returns a `Future<RandomAccessFile>` that completes with this
+  /// [RandomAccessFile] when the write completes.
   Future<RandomAccessFile> writeFrom(List<int> buffer,
       [int start = 0, int? end]);
 
-  /**
-   * Synchronously writes from a [List<int>] to the file. It will read the
-   * buffer from index [start] to index [end]. If [start] is omitted, it'll
-   * start from index 0. If [end] is omitted, it will write to the end of
-   * [buffer].
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously writes from a [buffer] to the file.
+  ///
+  /// Will read the buffer from index [start] to index [end].
+  /// The [start] must be non-negative and no greater than `buffer.length`.
+  /// If [end] is omitted, it defaults to [buffer.length].
+  /// Otherwise [end] must be no less than [start]
+  /// and no greater than `buffer.length`.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   void writeFromSync(List<int> buffer, [int start = 0, int? end]);
 
-  /**
-   * Writes a string to the file using the given [Encoding]. Returns a
-   * `Future<RandomAccessFile>` that completes with this
-   * RandomAccessFile when the write completes.
-   */
+  /// Writes a string to the file using the given [Encoding].
+  ///
+  /// Returns a `Future<RandomAccessFile>` that completes with this
+  /// random access file when the write completes.
   Future<RandomAccessFile> writeString(String string,
-      {Encoding encoding: utf8});
+      {Encoding encoding = utf8});
 
-  /**
-   * Synchronously writes a single string to the file using the given
-   * [Encoding].
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
-  void writeStringSync(String string, {Encoding encoding: utf8});
+  /// Synchronously writes a single string to the file using the given
+  /// [Encoding].
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
+  void writeStringSync(String string, {Encoding encoding = utf8});
 
-  /**
-   * Gets the current byte position in the file. Returns a
-   * `Future<int>` that completes with the position.
-   */
+  /// Gets the current byte position in the file.
+  ///
+  /// Returns a `Future<int>` that completes with the position.
   Future<int> position();
 
-  /**
-   * Synchronously gets the current byte position in the file.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously gets the current byte position in the file.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   int positionSync();
 
-  /**
-   * Sets the byte position in the file. Returns a
-   * `Future<RandomAccessFile>` that completes with this
-   * RandomAccessFile when the position has been set.
-   */
+  /// Sets the byte position in the file.
+  ///
+  /// Returns a `Future<RandomAccessFile>` that completes with this
+  /// random access file when the position has been set.
   Future<RandomAccessFile> setPosition(int position);
 
-  /**
-   * Synchronously sets the byte position in the file.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously sets the byte position in the file.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   void setPositionSync(int position);
 
-  /**
-   * Truncates (or extends) the file to [length] bytes. Returns a
-   * `Future<RandomAccessFile>` that completes with this
-   * RandomAccessFile when the truncation has been performed.
-   */
+  /// Truncates (or extends) the file to [length] bytes.
+  ///
+  /// Returns a `Future<RandomAccessFile>` that completes with this
+  /// random access file when the truncation has been performed.
   Future<RandomAccessFile> truncate(int length);
 
-  /**
-   * Synchronously truncates (or extends) the file to [length] bytes.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously truncates (or extends) the file to [length] bytes.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   void truncateSync(int length);
 
-  /**
-   * Gets the length of the file. Returns a `Future<int>` that
-   * completes with the length in bytes.
-   */
+  /// Gets the length of the file.
+  ///
+  /// Returns a `Future<int>` that completes with the length in bytes.
   Future<int> length();
 
-  /**
-   * Synchronously gets the length of the file.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously gets the length of the file.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   int lengthSync();
 
-  /**
-   * Flushes the contents of the file to disk. Returns a
-   * `Future<RandomAccessFile>` that completes with this
-   * RandomAccessFile when the flush operation completes.
-   */
+  /// Flushes the contents of the file to disk.
+  ///
+  /// Returns a `Future<RandomAccessFile>` that completes with this
+  /// random access file when the flush operation completes.
   Future<RandomAccessFile> flush();
 
-  /**
-   * Synchronously flushes the contents of the file to disk.
-   *
-   * Throws a [FileSystemException] if the operation fails.
-   */
+  /// Synchronously flushes the contents of the file to disk.
+  ///
+  /// Throws a [FileSystemException] if the operation fails.
   void flushSync();
 
-  /**
-   * Locks the file or part of the file.
-   *
-   * By default an exclusive lock will be obtained, but that can be overridden
-   * by the [mode] argument.
-   *
-   * Locks the byte range from [start] to [end] of the file, with the
-   * byte at position `end` not included. If no arguments are
-   * specified, the full file is locked, If only `start` is specified
-   * the file is locked from byte position `start` to the end of the
-   * file, no matter how large it grows. It is possible to specify an
-   * explicit value of `end` which is past the current length of the file.
-   *
-   * To obtain an exclusive lock on a file it must be opened for writing.
-   *
-   * If [mode] is [FileLock.exclusive] or [FileLock.shared], an error is
-   * signaled if the lock cannot be obtained. If [mode] is
-   * [FileLock.blockingExclusive] or [FileLock.blockingShared], the
-   * returned [Future] is resolved only when the lock has been obtained.
-   *
-   * *NOTE* file locking does have slight differences in behavior across
-   * platforms:
-   *
-   * On Linux and OS X this uses advisory locks, which have the
-   * surprising semantics that all locks associated with a given file
-   * are removed when *any* file descriptor for that file is closed by
-   * the process. Note that this does not actually lock the file for
-   * access. Also note that advisory locks are on a process
-   * level. This means that several isolates in the same process can
-   * obtain an exclusive lock on the same file.
-   *
-   * On Windows the regions used for lock and unlock needs to match. If that
-   * is not the case unlocking will result in the OS error "The segment is
-   * already unlocked".
-   */
+  /// Locks the file or part of the file.
+  ///
+  /// By default an exclusive lock will be obtained, but that can be overridden
+  /// by the [mode] argument.
+  ///
+  /// Locks the byte range from [start] to [end] of the file, with the
+  /// byte at position `end` not included. If no arguments are
+  /// specified, the full file is locked, If only `start` is specified
+  /// the file is locked from byte position `start` to the end of the
+  /// file, no matter how large it grows. It is possible to specify an
+  /// explicit value of `end` which is past the current length of the file.
+  ///
+  /// To obtain an exclusive lock on a file, it must be opened for writing.
+  ///
+  /// If [mode] is [FileLock.exclusive] or [FileLock.shared], an error is
+  /// signaled if the lock cannot be obtained. If [mode] is
+  /// [FileLock.blockingExclusive] or [FileLock.blockingShared], the
+  /// returned [Future] is resolved only when the lock has been obtained.
+  ///
+  /// *NOTE* file locking does have slight differences in behavior across
+  /// platforms:
+  ///
+  /// On Linux and OS X this uses advisory locks, which have the
+  /// surprising semantics that all locks associated with a given file
+  /// are removed when *any* file descriptor for that file is closed by
+  /// the process. Note that this does not actually lock the file for
+  /// access. Also note that advisory locks are on a process
+  /// level. This means that several isolates in the same process can
+  /// obtain an exclusive lock on the same file.
+  ///
+  /// On Windows the regions used for lock and unlock needs to match. If that
+  /// is not the case unlocking will result in the OS error "The segment is
+  /// already unlocked".
   Future<RandomAccessFile> lock(
       [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]);
 
-  /**
-   * Synchronously locks the file or part of the file.
-   *
-   * By default an exclusive lock will be obtained, but that can be overridden
-   * by the [mode] argument.
-   *
-   * Locks the byte range from [start] to [end] of the file ,with the
-   * byte at position `end` not included. If no arguments are
-   * specified, the full file is locked, If only `start` is specified
-   * the file is locked from byte position `start` to the end of the
-   * file, no matter how large it grows. It is possible to specify an
-   * explicit value of `end` which is past the current length of the file.
-   *
-   * To obtain an exclusive lock on a file it must be opened for writing.
-   *
-   * If [mode] is [FileLock.exclusive] or [FileLock.shared], an exception is
-   * thrown if the lock cannot be obtained. If [mode] is
-   * [FileLock.blockingExclusive] or [FileLock.blockingShared], the
-   * call returns only after the lock has been obtained.
-   *
-   * *NOTE* file locking does have slight differences in behavior across
-   * platforms:
-   *
-   * On Linux and OS X this uses advisory locks, which have the
-   * surprising semantics that all locks associated with a given file
-   * are removed when *any* file descriptor for that file is closed by
-   * the process. Note that this does not actually lock the file for
-   * access. Also note that advisory locks are on a process
-   * level. This means that several isolates in the same process can
-   * obtain an exclusive lock on the same file.
-   *
-   * On Windows the regions used for lock and unlock needs to match. If that
-   * is not the case unlocking will result in the OS error "The segment is
-   * already unlocked".
-   *
-   */
+  /// Synchronously locks the file or part of the file.
+  ///
+  /// By default an exclusive lock will be obtained, but that can be overridden
+  /// by the [mode] argument.
+  ///
+  /// Locks the byte range from [start] to [end] of the file ,with the
+  /// byte at position `end` not included. If no arguments are
+  /// specified, the full file is locked, If only `start` is specified
+  /// the file is locked from byte position `start` to the end of the
+  /// file, no matter how large it grows. It is possible to specify an
+  /// explicit value of `end` which is past the current length of the file.
+  ///
+  /// To obtain an exclusive lock on a file it must be opened for writing.
+  ///
+  /// If [mode] is [FileLock.exclusive] or [FileLock.shared], an exception is
+  /// thrown if the lock cannot be obtained. If [mode] is
+  /// [FileLock.blockingExclusive] or [FileLock.blockingShared], the
+  /// call returns only after the lock has been obtained.
+  ///
+  /// *NOTE* file locking does have slight differences in behavior across
+  /// platforms:
+  ///
+  /// On Linux and OS X this uses advisory locks, which have the
+  /// surprising semantics that all locks associated with a given file
+  /// are removed when *any* file descriptor for that file is closed by
+  /// the process. Note that this does not actually lock the file for
+  /// access. Also note that advisory locks are on a process
+  /// level. This means that several isolates in the same process can
+  /// obtain an exclusive lock on the same file.
+  ///
+  /// On Windows the regions used for lock and unlock needs to match. If that
+  /// is not the case unlocking will result in the OS error "The segment is
+  /// already unlocked".
+  ///
   void lockSync(
       [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]);
 
-  /**
-   * Unlocks the file or part of the file.
-   *
-   * Unlocks the byte range from [start] to [end] of the file, with
-   * the byte at position `end` not included. If no arguments are
-   * specified, the full file is unlocked, If only `start` is
-   * specified the file is unlocked from byte position `start` to the
-   * end of the file.
-   *
-   * *NOTE* file locking does have slight differences in behavior across
-   * platforms:
-   *
-   * See [lock] for more details.
-   */
+  /// Unlocks the file or part of the file.
+  ///
+  /// Unlocks the byte range from [start] to [end] of the file, with
+  /// the byte at position `end` not included. If no arguments are
+  /// specified, the full file is unlocked, If only `start` is
+  /// specified the file is unlocked from byte position `start` to the
+  /// end of the file.
+  ///
+  /// *NOTE* file locking does have slight differences in behavior across
+  /// platforms:
+  ///
+  /// See [lock] for more details.
   Future<RandomAccessFile> unlock([int start = 0, int end = -1]);
 
-  /**
-   * Synchronously unlocks the file or part of the file.
-   *
-   * Unlocks the byte range from [start] to [end] of the file, with
-   * the byte at position `end` not included. If no arguments are
-   * specified, the full file is unlocked, If only `start` is
-   * specified the file is unlocked from byte position `start` to the
-   * end of the file.
-   *
-   * *NOTE* file locking does have slight differences in behavior across
-   * platforms:
-   *
-   * See [lockSync] for more details.
-   */
+  /// Synchronously unlocks the file or part of the file.
+  ///
+  /// Unlocks the byte range from [start] to [end] of the file, with
+  /// the byte at position `end` not included. If no arguments are
+  /// specified, the full file is unlocked, If only `start` is
+  /// specified the file is unlocked from byte position `start` to the
+  /// end of the file.
+  ///
+  /// *NOTE* file locking does have slight differences in behavior across
+  /// platforms:
+  ///
+  /// See [lockSync] for more details.
   void unlockSync([int start = 0, int end = -1]);
 
-  /**
-   * Returns a human-readable string for this RandomAccessFile instance.
-   */
+  /// Returns a human-readable string for this random access file.
   String toString();
 
-  /**
-   * Gets the path of the file underlying this RandomAccessFile.
-   */
+  /// The path of the file underlying this random access file.
   String get path;
 }
 
-/**
- * Exception thrown when a file operation fails.
- */
+/// Exception thrown when a file operation fails.
 @pragma("vm:entry-point")
 class FileSystemException implements IOException {
-  /**
-   * Message describing the error. This does not include any detailed
-   * information form the underlying OS error. Check [osError] for
-   * that information.
-   */
+  /// Message describing the error.
+  ///
+  /// The message does not include any detailed information from
+  /// the underlying OS error. Check [osError] for that information.
   final String message;
 
-  /**
-   * The file system path on which the error occurred. Can be `null`
-   * if the exception does not relate directly to a file system path.
-   */
+  /// The file system path on which the error occurred.
+  ///
+  /// Can be `null` if the exception does not relate directly
+  /// to a file system path.
   final String? path;
 
-  /**
-   * The underlying OS error. Can be `null` if the exception is not
-   * raised due to an OS error.
-   */
+  /// The underlying OS error.
+  ///
+  /// Can be `null` if the exception is not raised due to an OS error.
   final OSError? osError;
 
-  /**
-   * Creates a new FileSystemException with an optional error message
-   * [message], optional file system path [path] and optional OS error
-   * [osError].
-   */
+  /// Creates a new file system exception with optional parts.
+  ///
+  /// Creates an exception with [FileSystemException.message],
+  /// [FileSystemException.path] and [FileSystemException.osError]
+  /// values take from the optional parameters of the same name.
+  ///
+  /// The [message] and [path] path defaults to empty strings if omitted,
+  /// and [osError] defaults to `null`.
   @pragma("vm:entry-point")
   const FileSystemException([this.message = "", this.path = "", this.osError]);
 
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 75f78b1..696273b 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -244,7 +244,7 @@
 
   File get absolute => new File(_absolutePath);
 
-  Future<File> create({bool recursive: false}) {
+  Future<File> create({bool recursive = false}) {
     var result =
         recursive ? parent.create(recursive: true) : new Future.value(null);
     return result
@@ -265,7 +265,7 @@
 
   external static _linkTarget(_Namespace namespace, Uint8List rawPath);
 
-  void createSync({bool recursive: false}) {
+  void createSync({bool recursive = false}) {
     if (recursive) {
       parent.createSync(recursive: true);
     }
@@ -273,7 +273,7 @@
     throwIfError(result, "Cannot create file", path);
   }
 
-  Future<File> _delete({bool recursive: false}) {
+  Future<File> _delete({bool recursive = false}) {
     if (recursive) {
       return new Directory(path).delete(recursive: true).then((_) => this);
     }
@@ -290,7 +290,7 @@
 
   external static _deleteLinkNative(_Namespace namespace, Uint8List rawPath);
 
-  void _deleteSync({bool recursive: false}) {
+  void _deleteSync({bool recursive = false}) {
     if (recursive) {
       return new Directory.fromRawPath(_rawPath).deleteSync(recursive: true);
     }
@@ -341,7 +341,7 @@
     return new File(newPath);
   }
 
-  Future<RandomAccessFile> open({FileMode mode: FileMode.read}) {
+  Future<RandomAccessFile> open({FileMode mode = FileMode.read}) {
     if (mode != FileMode.read &&
         mode != FileMode.write &&
         mode != FileMode.append &&
@@ -467,7 +467,7 @@
 
   external static _open(_Namespace namespace, Uint8List rawPath, int mode);
 
-  RandomAccessFile openSync({FileMode mode: FileMode.read}) {
+  RandomAccessFile openSync({FileMode mode = FileMode.read}) {
     if (mode != FileMode.read &&
         mode != FileMode.write &&
         mode != FileMode.append &&
@@ -494,7 +494,7 @@
     return new _FileStream(path, start, end);
   }
 
-  IOSink openWrite({FileMode mode: FileMode.write, Encoding encoding: utf8}) {
+  IOSink openWrite({FileMode mode = FileMode.write, Encoding encoding = utf8}) {
     if (mode != FileMode.write &&
         mode != FileMode.append &&
         mode != FileMode.writeOnly &&
@@ -566,7 +566,7 @@
     }
   }
 
-  Future<String> readAsString({Encoding encoding: utf8}) {
+  Future<String> readAsString({Encoding encoding = utf8}) {
     // TODO(dart:io): If the change in async semantics to run synchronously
     // until await lands, this is as efficient as
     // return _tryDecode(await readAsBytes(), encoding);
@@ -580,17 +580,17 @@
     });
   }
 
-  String readAsStringSync({Encoding encoding: utf8}) =>
+  String readAsStringSync({Encoding encoding = utf8}) =>
       _tryDecode(readAsBytesSync(), encoding);
 
-  Future<List<String>> readAsLines({Encoding encoding: utf8}) =>
+  Future<List<String>> readAsLines({Encoding encoding = utf8}) =>
       readAsString(encoding: encoding).then(const LineSplitter().convert);
 
-  List<String> readAsLinesSync({Encoding encoding: utf8}) =>
+  List<String> readAsLinesSync({Encoding encoding = utf8}) =>
       const LineSplitter().convert(readAsStringSync(encoding: encoding));
 
   Future<File> writeAsBytes(List<int> bytes,
-      {FileMode mode: FileMode.write, bool flush: false}) {
+      {FileMode mode = FileMode.write, bool flush = false}) {
     return open(mode: mode).then((file) {
       return file.writeFrom(bytes, 0, bytes.length).then<File>((_) {
         if (flush) return file.flush().then((_) => this);
@@ -600,7 +600,7 @@
   }
 
   void writeAsBytesSync(List<int> bytes,
-      {FileMode mode: FileMode.write, bool flush: false}) {
+      {FileMode mode = FileMode.write, bool flush = false}) {
     RandomAccessFile opened = openSync(mode: mode);
     try {
       opened.writeFromSync(bytes, 0, bytes.length);
@@ -611,9 +611,9 @@
   }
 
   Future<File> writeAsString(String contents,
-      {FileMode mode: FileMode.write,
-      Encoding encoding: utf8,
-      bool flush: false}) {
+      {FileMode mode = FileMode.write,
+      Encoding encoding = utf8,
+      bool flush = false}) {
     try {
       return writeAsBytes(encoding.encode(contents), mode: mode, flush: flush);
     } catch (e) {
@@ -622,9 +622,9 @@
   }
 
   void writeAsStringSync(String contents,
-      {FileMode mode: FileMode.write,
-      Encoding encoding: utf8,
-      bool flush: false}) {
+      {FileMode mode = FileMode.write,
+      Encoding encoding = utf8,
+      bool flush = false}) {
     writeAsBytesSync(encoding.encode(contents), mode: mode, flush: flush);
   }
 
@@ -873,14 +873,14 @@
   }
 
   Future<RandomAccessFile> writeString(String string,
-      {Encoding encoding: utf8}) {
+      {Encoding encoding = utf8}) {
     // TODO(40614): Remove once non-nullability is sound.
     ArgumentError.checkNotNull(encoding, "encoding");
     var data = encoding.encode(string);
     return writeFrom(data, 0, data.length);
   }
 
-  void writeStringSync(String string, {Encoding encoding: utf8}) {
+  void writeStringSync(String string, {Encoding encoding = utf8}) {
     // TODO(40614): Remove once non-nullability is sound.
     ArgumentError.checkNotNull(encoding, "encoding");
     var data = encoding.encode(string);
@@ -1058,7 +1058,7 @@
   // count when it is finished with it.
   int _pointer() => _ops.getPointer();
 
-  Future _dispatch(int request, List data, {bool markClosed: false}) {
+  Future _dispatch(int request, List data, {bool markClosed = false}) {
     if (closed) {
       return new Future.error(new FileSystemException("File closed", path));
     }
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 0e12414..e624473 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -4,14 +4,11 @@
 
 part of dart.io;
 
-/**
- * The type of an entity on the file system, such as a file, directory, or link.
- *
- * These constants are used by the [FileSystemEntity] class
- * to indicate the object's type.
- *
- */
-
+/// The type of an entity on the file system,
+/// such as a file, directory, or link.
+///
+/// These constants are used by the [FileSystemEntity] class
+/// to indicate the object's type.
 class FileSystemEntityType {
   static const file = const FileSystemEntityType._internal(0);
   @Deprecated("Use file instead")
@@ -43,11 +40,10 @@
   String toString() => const ['file', 'directory', 'link', 'notFound'][_type];
 }
 
-/**
- * A FileStat object represents the result of calling the POSIX stat() function
- * on a file system object.  It is an immutable object, representing the
- * snapshotted values returned by the stat() call.
- */
+/// The result of calling the POSIX `stat()` function on a file system object.
+///
+/// This is an immutable object, representing the snapshotted values returned
+/// by the `stat()` call.
 class FileStat {
   // These must agree with enum FileStat in file.h.
   static const _type = 0;
@@ -61,45 +57,33 @@
   static final _notFound = new FileStat._internal(
       _epoch, _epoch, _epoch, FileSystemEntityType.notFound, 0, -1);
 
-  /**
-   * The time of the last change to the data or metadata of the file system
-   * object.
-   *
-   * On Windows platforms, this is instead the file creation time.
-   */
+  /// The time of the last change to the data or metadata of the file system
+  /// object.
+  ///
+  /// On Windows platforms, this is instead the file creation time.
   final DateTime changed;
 
-  /**
-   * The time of the last change to the data of the file system object.
-   */
+  /// The time of the last change to the data of the file system object.
   final DateTime modified;
 
-  /**
-   * The time of the last access to the data of the file system object.
-   *
-   * On Windows platforms, this may have 1 day granularity, and be
-   * out of date by an hour.
-   */
+  /// The time of the last access to the data of the file system object.
+  ///
+  /// On Windows platforms, this may have 1 day granularity, and be
+  /// out of date by an hour.
   final DateTime accessed;
 
-  /**
-   * The type of the underlying file system object.
-   *
-   * [FileSystemEntityType.notFound] if [stat] or [statSync] failed.
-   */
+  /// The type of the underlying file system object.
+  ///
+  /// [FileSystemEntityType.notFound] if [stat] or [statSync] failed.
   final FileSystemEntityType type;
 
-  /**
-   * The mode of the file system object.
-   *
-   * Permissions are encoded in the lower 16 bits of this number, and can be
-   * decoded using the [modeString] getter.
-   */
+  /// The mode of the file system object.
+  ///
+  /// Permissions are encoded in the lower 16 bits of this number, and can be
+  /// decoded using the [modeString] getter.
   final int mode;
 
-  /**
-   * The size of the file system object.
-   */
+  /// The size of the file system object.
   final int size;
 
   FileStat._internal(this.changed, this.modified, this.accessed, this.type,
@@ -107,13 +91,11 @@
 
   external static _statSync(_Namespace namespace, String path);
 
-  /**
-   * Calls the operating system's `stat()` function (or equivalent) on [path].
-   *
-   * Returns a [FileStat] object containing the data returned by `stat()`.
-   * If the call fails, returns a [FileStat] object with [FileStat.type] set to
-   * [FileSystemEntityType.notFound] and the other fields invalid.
-   */
+  /// Calls the operating system's `stat()` function (or equivalent) on [path].
+  ///
+  /// Returns a [FileStat] object containing the data returned by `stat()`.
+  /// If the call fails, returns a [FileStat] object with [FileStat.type] set to
+  /// [FileSystemEntityType.notFound] and the other fields invalid.
   static FileStat statSync(String path) {
     final IOOverrides? overrides = IOOverrides.current;
     if (overrides == null) {
@@ -138,12 +120,10 @@
         data[_size]);
   }
 
-  /**
-   * Asynchronously calls the operating system's `stat()` function (or
-   * equivalent) on [path].
-   *
-   * Returns a [Future] which completes with the same results as [statSync].
-   */
+  /// Asynchronously calls the operating system's `stat()` function (or
+  /// equivalent) on [path].
+  ///
+  /// Returns a [Future] which completes with the same results as [statSync].
   static Future<FileStat> stat(String path) {
     final IOOverrides? overrides = IOOverrides.current;
     if (overrides == null) {
@@ -182,15 +162,13 @@
           mode ${modeString()}
           size $size""";
 
-  /**
-   * Returns the mode value as a human-readable string.
-   *
-   * The string is in the format "rwxrwxrwx", reflecting the user, group, and
-   * world permissions to read, write, and execute the file system object, with
-   * "-" replacing the letter for missing permissions.  Extra permission bits
-   * may be represented by prepending "(suid)", "(guid)", and/or "(sticky)" to
-   * the mode string.
-   */
+  /// The mode value as a human-readable string.
+  ///
+  /// The string is in the format "rwxrwxrwx", reflecting the user, group, and
+  /// world permissions to read, write, and execute the file system object, with
+  /// "-" replacing the letter for missing permissions. Extra permission bits
+  /// may be represented by prepending "(suid)", "(guid)", and/or "(sticky)" to
+  /// the mode string.
   String modeString() {
     var permissions = mode & 0xFFF;
     var codes = const ['---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx'];
@@ -206,39 +184,36 @@
   }
 }
 
-/**
- * The common super class for [File], [Directory], and [Link] objects.
- *
- * [FileSystemEntity] objects are returned from directory listing
- * operations. To determine if a FileSystemEntity is a [File], a
- * [Directory], or a [Link] perform a type check:
- *
- *     if (entity is File) (entity as File).readAsStringSync();
- *
- * You can also use the [type] or [typeSync] methods to determine
- * the type of a file system object.
- *
- * Most methods in this class occur in synchronous and asynchronous pairs,
- * for example, [exists] and [existsSync].
- * Unless you have a specific reason for using the synchronous version
- * of a method, prefer the asynchronous version to avoid blocking your program.
- *
- * Here's the exists method in action:
- *
- *     entity.exists().then((isThere) {
- *       isThere ? print('exists') : print('non-existent');
- *     });
- *
- *
- * ## Other resources
- *
- * * The [Files and directories](https://dart.dev/guides/libraries/library-tour#files-and-directories)
- *   section of the library tour.
- *
- * * [Write Command-Line Apps](https://dart.dev/tutorials/server/cmdline),
- *   a tutorial about writing command-line apps, includes information about
- *   files and directories.
- */
+/// The common superclass of [File], [Directory], and [Link].
+///
+/// [FileSystemEntity] objects are returned from directory listing
+/// operations. To determine whether a [FileSystemEntity] is a [File], a
+/// [Directory], or a [Link] perform a type check:
+/// ```dart
+/// if (entity is File) (entity as File).readAsStringSync();
+/// ```
+/// You can also use the [type] or [typeSync] methods to determine
+/// the type of a file system object.
+///
+/// Most methods in this class exist both in synchronous and asynchronous
+/// versions, for example, [exists] and [existsSync].
+/// Unless you have a specific reason for using the synchronous version
+/// of a method, prefer the asynchronous version to avoid blocking your program.
+///
+/// Here's the exists method in action:
+/// ```dart
+/// var isThere = await entity.exists();
+/// print(isThere ? 'exists' : 'non-existent');
+/// ```
+///
+/// ## Other resources
+///
+/// * The [Files and directories](https://dart.dev/guides/libraries/library-tour#files-and-directories)
+///   section of the library tour.
+///
+/// * [Write Command-Line Apps](https://dart.dev/tutorials/server/cmdline),
+///   a tutorial about writing command-line apps, includes information about
+///   files and directories.
 abstract class FileSystemEntity {
   static const _backslashChar = 0x5c;
   static const _slashChar = 0x2f;
@@ -249,98 +224,87 @@
 
   String get path;
 
-  /**
-   * Returns a [Uri] representing the file system entity's location.
-   *
-   * The returned URI's scheme is always "file" if the entity's [path] is
-   * absolute, otherwise the scheme will be empty.
-   */
+  /// A [Uri] representing the file system entity's location.
+  ///
+  /// The returned URI's scheme is always "file" if the entity's [path] is
+  /// absolute, otherwise the scheme will be empty and the URI relative.
   Uri get uri => new Uri.file(path);
 
-  /**
-   * Checks whether the file system entity with this path exists. Returns
-   * a [:Future<bool>:] that completes with the result.
-   *
-   * Since FileSystemEntity is abstract, every FileSystemEntity object
-   * is actually an instance of one of the subclasses [File],
-   * [Directory], and [Link].  Calling [exists] on an instance of one
-   * of these subclasses checks whether the object exists in the file
-   * system object exists and is of the correct type (file, directory,
-   * or link).  To check whether a path points to an object on the
-   * file system, regardless of the object's type, use the [type]
-   * static method.
-   *
-   */
+  /// Checks whether the file system entity with this path exists.
+  ///
+  /// Returns a `Future<bool>` that completes with the result.
+  ///
+  /// Since [FileSystemEntity] is abstract, every [FileSystemEntity] object
+  /// is actually an instance of one of the subclasses [File],
+  /// [Directory], and [Link]. Calling [exists] on an instance of one
+  /// of these subclasses checks whether the object exists in the file
+  /// system object exists *and* is of the correct type (file, directory,
+  /// or link). To check whether a path points to an object on the
+  /// file system, regardless of the object's type, use the [type]
+  /// static method.
   Future<bool> exists();
 
-  /**
-   * Synchronously checks whether the file system entity with this path
-   * exists.
-   *
-   * Since FileSystemEntity is abstract, every FileSystemEntity object
-   * is actually an instance of one of the subclasses [File],
-   * [Directory], and [Link].  Calling [existsSync] on an instance of
-   * one of these subclasses checks whether the object exists in the
-   * file system object exists and is of the correct type (file,
-   * directory, or link).  To check whether a path points to an object
-   * on the file system, regardless of the object's type, use the
-   * [typeSync] static method.
-   */
+  /// Synchronously checks whether the file system entity with this path
+  /// exists.
+  ///
+  /// Since [FileSystemEntity] is abstract, every [FileSystemEntity] object
+  /// is actually an instance of one of the subclasses [File],
+  /// [Directory], and [Link].  Calling [existsSync] on an instance of
+  /// one of these subclasses checks whether the object exists in the
+  /// file system object exists and is of the correct type (file,
+  /// directory, or link).  To check whether a path points to an object
+  /// on the file system, regardless of the object's type, use the
+  /// [typeSync] static method.
   bool existsSync();
 
-  /**
-   * Renames this file system entity.
-   *
-   * Returns a `Future<FileSystemEntity>` that completes with a
-   * [FileSystemEntity] instance for the renamed file system entity.
-   *
-   * If [newPath] identifies an existing entity of the same type, that entity
-   * is replaced. If [newPath] identifies an existing entity of a different
-   * type, the operation fails and the future completes with an exception.
-   */
+  /// Renames this file system entity.
+  ///
+  /// Returns a `Future<FileSystemEntity>` that completes with a
+  /// [FileSystemEntity] instance for the renamed file system entity.
+  ///
+  /// If [newPath] identifies an existing entity of the same type,
+  /// that entity is removed first.
+  /// If [newPath] identifies an existing entity of a different type,
+  /// the operation fails and the future completes with an exception.
   Future<FileSystemEntity> rename(String newPath);
 
-  /**
-   * Synchronously renames this file system entity.
-   *
-   * Returns a [FileSystemEntity] instance for the renamed entity.
-   *
-   * If [newPath] identifies an existing entity of the same type, that entity
-   * is replaced. If [newPath] identifies an existing entity of a different
-   * type, the operation fails and an exception is thrown.
-   */
+  /// Synchronously renames this file system entity.
+  ///
+  /// Returns a [FileSystemEntity] instance for the renamed entity.
+  ///
+  /// If [newPath] identifies an existing entity of the same type,
+  /// that entity is removed first.
+  /// If [newPath] identifies an existing entity of a different type,
+  /// the operation fails and an exception is thrown.
   FileSystemEntity renameSync(String newPath);
 
-  /**
-   * Resolves the path of a file system object relative to the
-   * current working directory.
-   *
-   * Resolves all symbolic links on the path and resolves all `..` and `.` path
-   * segments.
-   *
-   * [resolveSymbolicLinks] uses the operating system's native
-   * file system API to resolve the path, using the `realpath` function
-   * on linux and OS X, and the `GetFinalPathNameByHandle` function on
-   * Windows. If the path does not point to an existing file system object,
-   * `resolveSymbolicLinks` throws a `FileSystemException`.
-   *
-   * On Windows the `..` segments are resolved _before_ resolving the symbolic
-   * link, and on other platforms the symbolic links are _resolved to their
-   * target_ before applying a `..` that follows.
-   *
-   * To ensure the same behavior on all platforms resolve `..` segments before
-   * calling `resolveSymbolicLinks`. One way of doing this is with the `Uri`
-   * class:
-   *
-   *     var path = Uri.parse('.').resolveUri(new Uri.file(input)).toFilePath();
-   *     if (path == '') path = '.';
-   *     new File(path).resolveSymbolicLinks().then((resolved) {
-   *       print(resolved);
-   *     });
-   *
-   * since `Uri.resolve` removes `..` segments. This will result in the Windows
-   * behavior.
-   */
+  /// Resolves the path of a file system object relative to the
+  /// current working directory.
+  ///
+  /// Resolves all symbolic links on the path and resolves all `..` and `.` path
+  /// segments.
+  ///
+  /// [resolveSymbolicLinks] uses the operating system's native
+  /// file system API to resolve the path, using the `realpath` function
+  /// on Linux and OS X, and the `GetFinalPathNameByHandle` function on
+  /// Windows. If the path does not point to an existing file system object,
+  /// `resolveSymbolicLinks` throws a `FileSystemException`.
+  ///
+  /// On Windows the `..` segments are resolved _before_ resolving the symbolic
+  /// link, and on other platforms the symbolic links are _resolved to their
+  /// target_ before applying a `..` that follows.
+  ///
+  /// To ensure the same behavior on all platforms resolve `..` segments before
+  /// calling `resolveSymbolicLinks`. One way of doing this is with the [Uri]
+  /// class:
+  /// ```dart
+  /// var path = Uri.parse('.').resolveUri(Uri.file(input)).toFilePath();
+  /// if (path == '') path = '.';
+  /// var resolved = await File(path).resolveSymbolicLinks();
+  /// print(resolved);
+  /// ```
+  /// since `Uri.resolve` removes `..` segments. This will result in the Windows
+  /// behavior.
   Future<String> resolveSymbolicLinks() {
     return _File._dispatchWithNamespace(
         _IOService.fileResolveSymbolicLinks, [null, _rawPath]).then((response) {
@@ -352,143 +316,130 @@
     });
   }
 
-  /**
-   * Resolves the path of a file system object relative to the
-   * current working directory.
-   *
-   * Resolves all symbolic links on the path and resolves all `..` and `.` path
-   * segments.
-   *
-   * [resolveSymbolicLinksSync] uses the operating system's native
-   * file system API to resolve the path, using the `realpath` function
-   * on linux and OS X, and the `GetFinalPathNameByHandle` function on
-   * Windows. If the path does not point to an existing file system object,
-   * `resolveSymbolicLinksSync` throws a `FileSystemException`.
-   *
-   * On Windows the `..` segments are resolved _before_ resolving the symbolic
-   * link, and on other platforms the symbolic links are _resolved to their
-   * target_ before applying a `..` that follows.
-   *
-   * To ensure the same behavior on all platforms resolve `..` segments before
-   * calling `resolveSymbolicLinksSync`. One way of doing this is with the `Uri`
-   * class:
-   *
-   *     var path = Uri.parse('.').resolveUri(new Uri.file(input)).toFilePath();
-   *     if (path == '') path = '.';
-   *     var resolved = new File(path).resolveSymbolicLinksSync();
-   *     print(resolved);
-   *
-   * since `Uri.resolve` removes `..` segments. This will result in the Windows
-   * behavior.
-   */
+  /// Resolves the path of a file system object relative to the
+  /// current working directory.
+  ///
+  /// Resolves all symbolic links on the path and resolves all `..` and `.` path
+  /// segments.
+  ///
+  /// [resolveSymbolicLinksSync] uses the operating system's native
+  /// file system API to resolve the path, using the `realpath` function
+  /// on linux and OS X, and the `GetFinalPathNameByHandle` function on
+  /// Windows. If the path does not point to an existing file system object,
+  /// `resolveSymbolicLinksSync` throws a `FileSystemException`.
+  ///
+  /// On Windows the `..` segments are resolved _before_ resolving the symbolic
+  /// link, and on other platforms the symbolic links are _resolved to their
+  /// target_ before applying a `..` that follows.
+  ///
+  /// To ensure the same behavior on all platforms resolve `..` segments before
+  /// calling `resolveSymbolicLinksSync`. One way of doing this is with the [Uri]
+  /// class:
+  /// ```dart
+  /// var path = Uri.parse('.').resolveUri(Uri.file(input)).toFilePath();
+  /// if (path == '') path = '.';
+  /// var resolved = File(path).resolveSymbolicLinksSync();
+  /// print(resolved);
+  /// ```
+  /// since `Uri.resolve` removes `..` segments. This will result in the Windows
+  /// behavior.
   String resolveSymbolicLinksSync() {
     var result = _resolveSymbolicLinks(_Namespace._namespace, _rawPath);
     _throwIfError(result, "Cannot resolve symbolic links", path);
     return result;
   }
 
-  /**
-   * Calls the operating system's stat() function on the [path] of this
-   * [FileSystemEntity].
-   *
-   * Identical to [:FileStat.stat(this.path):].
-   *
-   * Returns a [:Future<FileStat>:] object containing the data returned by
-   * stat().
-   *
-   * If the call fails, completes the future with a [FileStat] object
-   * with `.type` set to [FileSystemEntityType.notFound] and the other fields
-   * invalid.
-   */
+  /// Calls the operating system's `stat()` function on [path].
+  ///
+  /// Identical to `FileStat.stat(this.path)`.
+  ///
+  /// Returns a `Future<FileStat>` object containing the data returned by
+  /// `stat()`.
+  ///
+  /// If the call fails, completes the future with a [FileStat] object
+  /// with `.type` set to [FileSystemEntityType.notFound] and the other fields
+  /// invalid.
   Future<FileStat> stat() => FileStat.stat(path);
 
-  /**
-   * Synchronously calls the operating system's stat() function on the
-   * [path] of this [FileSystemEntity].
-   *
-   * Identical to [:FileStat.statSync(this.path):].
-   *
-   * Returns a [FileStat] object containing the data returned by stat().
-   *
-   * If the call fails, returns a [FileStat] object with `.type` set to
-   * [FileSystemEntityType.notFound] and the other fields invalid.
-   */
+  /// Synchronously calls the operating system's `stat()` function on [path].
+  ///
+  /// Identical to `FileStat.statSync(this.path)`.
+  ///
+  /// Returns a [FileStat] object containing the data returned by `stat()`.
+  ///
+  /// If the call fails, returns a [FileStat] object with `.type` set to
+  /// [FileSystemEntityType.notFound] and the other fields invalid.
   FileStat statSync() => FileStat.statSync(path);
 
-  /**
-   * Deletes this [FileSystemEntity].
-   *
-   * If the [FileSystemEntity] is a directory, and if [recursive] is false,
-   * the directory must be empty. Otherwise, if [recursive] is true, the
-   * directory and all sub-directories and files in the directories are
-   * deleted. Links are not followed when deleting recursively. Only the link
-   * is deleted, not its target.
-   *
-   * If [recursive] is true, the [FileSystemEntity] is deleted even if the type
-   * of the [FileSystemEntity] doesn't match the content of the file system.
-   * This behavior allows [delete] to be used to unconditionally delete any file
-   * system object.
-   *
-   * Returns a [:Future<FileSystemEntity>:] that completes with this
-   * [FileSystemEntity] when the deletion is done. If the [FileSystemEntity]
-   * cannot be deleted, the future completes with an exception.
-   */
-  Future<FileSystemEntity> delete({bool recursive: false}) =>
+  /// Deletes this [FileSystemEntity].
+  ///
+  /// If the [FileSystemEntity] is a directory, and if [recursive] is `false`,
+  /// the directory must be empty. Otherwise, if [recursive] is true, the
+  /// directory and all sub-directories and files in the directories are
+  /// deleted. Links are not followed when deleting recursively. Only the link
+  /// is deleted, not its target.
+  ///
+  /// If [recursive] is true, the [FileSystemEntity] is deleted even if the type
+  /// of the [FileSystemEntity] doesn't match the content of the file system.
+  /// This behavior allows [delete] to be used to unconditionally delete any file
+  /// system object.
+  ///
+  /// Returns a `Future<FileSystemEntity>` that completes with this
+  /// [FileSystemEntity] when the deletion is done. If the [FileSystemEntity]
+  /// cannot be deleted, the future completes with an exception.
+  Future<FileSystemEntity> delete({bool recursive = false}) =>
       _delete(recursive: recursive);
 
-  /**
-   * Synchronously deletes this [FileSystemEntity].
-   *
-   * If the [FileSystemEntity] is a directory, and if [recursive] is false,
-   * the directory must be empty. Otherwise, if [recursive] is true, the
-   * directory and all sub-directories and files in the directories are
-   * deleted. Links are not followed when deleting recursively. Only the link
-   * is deleted, not its target.
-   *
-   * If [recursive] is true, the [FileSystemEntity] is deleted even if the type
-   * of the [FileSystemEntity] doesn't match the content of the file system.
-   * This behavior allows [deleteSync] to be used to unconditionally delete any
-   * file system object.
-   *
-   * Throws an exception if the [FileSystemEntity] cannot be deleted.
-   */
-  void deleteSync({bool recursive: false}) => _deleteSync(recursive: recursive);
+  /// Synchronously deletes this [FileSystemEntity].
+  ///
+  /// If the [FileSystemEntity] is a directory, and if [recursive] is false,
+  /// the directory must be empty. Otherwise, if [recursive] is true, the
+  /// directory and all sub-directories and files in the directories are
+  /// deleted. Links are not followed when deleting recursively. Only the link
+  /// is deleted, not its target.
+  ///
+  /// If [recursive] is true, the [FileSystemEntity] is deleted even if the type
+  /// of the [FileSystemEntity] doesn't match the content of the file system.
+  /// This behavior allows [deleteSync] to be used to unconditionally delete any
+  /// file system object.
+  ///
+  /// Throws an exception if the [FileSystemEntity] cannot be deleted.
+  void deleteSync({bool recursive = false}) =>
+      _deleteSync(recursive: recursive);
 
-  /**
-   * Start watching the [FileSystemEntity] for changes.
-   *
-   * The implementation uses platform-dependent event-based APIs for receiving
-   * file-system notifications, thus behavior depends on the platform.
-   *
-   *   * `Windows`: Uses `ReadDirectoryChangesW`. The implementation only
-   *     supports watching directories. Recursive watching is supported.
-   *   * `Linux`: Uses `inotify`. The implementation supports watching both
-   *     files and directories. Recursive watching is not supported.
-   *     Note: When watching files directly, delete events might not happen
-   *     as expected.
-   *   * `OS X`: Uses `FSEvents`. The implementation supports watching both
-   *     files and directories. Recursive watching is supported.
-   *
-   * The system will start listening for events once the returned [Stream] is
-   * being listened to, not when the call to [watch] is issued.
-   *
-   * The returned value is an endless broadcast [Stream], that only stops when
-   * one of the following happens:
-   *
-   *   * The [Stream] is canceled, e.g. by calling `cancel` on the
-   *      [StreamSubscription].
-   *   * The [FileSystemEntity] being watched, is deleted.
-   *   * System Watcher exits unexpectedly. e.g. On `Windows` this happens when
-   *     buffer that receive events from `ReadDirectoryChangesW` overflows.
-   *
-   * Use `events` to specify what events to listen for. The constants in
-   * [FileSystemEvent] can be or'ed together to mix events. Default is
-   * [FileSystemEvent.ALL].
-   *
-   * A move event may be reported as seperate delete and create events.
-   */
+  /// Start watching the [FileSystemEntity] for changes.
+  ///
+  /// The implementation uses platform-dependent event-based APIs for receiving
+  /// file-system notifications, thus behavior depends on the platform.
+  ///
+  ///   * `Windows`: Uses `ReadDirectoryChangesW`. The implementation only
+  ///     supports watching directories. Recursive watching is supported.
+  ///   * `Linux`: Uses `inotify`. The implementation supports watching both
+  ///     files and directories. Recursive watching is not supported.
+  ///     Note: When watching files directly, delete events might not happen
+  ///     as expected.
+  ///   * `OS X`: Uses `FSEvents`. The implementation supports watching both
+  ///     files and directories. Recursive watching is supported.
+  ///
+  /// The system will start listening for events once the returned [Stream] is
+  /// being listened to, not when the call to [watch] is issued.
+  ///
+  /// The returned value is an endless broadcast [Stream], that only stops when
+  /// one of the following happens:
+  ///
+  ///   * The [Stream] is canceled, e.g. by calling `cancel` on the
+  ///      [StreamSubscription].
+  ///   * The [FileSystemEntity] being watched is deleted.
+  ///   * System Watcher exits unexpectedly. e.g. On `Windows` this happens when
+  ///     buffer that receive events from `ReadDirectoryChangesW` overflows.
+  ///
+  /// Use `events` to specify what events to listen for. The constants in
+  /// [FileSystemEvent] can be or'ed together to mix events. Default is
+  /// [FileSystemEvent.ALL].
+  ///
+  /// A move event may be reported as seperate delete and create events.
   Stream<FileSystemEvent> watch(
-      {int events: FileSystemEvent.all, bool recursive: false}) {
+      {int events = FileSystemEvent.all, bool recursive = false}) {
     // FIXME(bkonyi): find a way to do this using the raw path.
     final String trimmedPath = _trimTrailingPathSeparators(path);
     final IOOverrides? overrides = IOOverrides.current;
@@ -498,8 +449,8 @@
     return overrides.fsWatch(trimmedPath, events, recursive);
   }
 
-  Future<FileSystemEntity> _delete({bool recursive: false});
-  void _deleteSync({bool recursive: false});
+  Future<FileSystemEntity> _delete({bool recursive = false});
+  void _deleteSync({bool recursive = false});
 
   static Future<bool> _identical(String path1, String path2) {
     return _File._dispatchWithNamespace(
@@ -512,20 +463,18 @@
     });
   }
 
-  /**
-   * Checks whether two paths refer to the same object in the
-   * file system.
-   *
-   * Returns a [:Future<bool>:] that completes with the result.
-   *
-   * Comparing a link to its target returns false, as does comparing two links
-   * that point to the same target.  To check the target of a link, use
-   * Link.target explicitly to fetch it.  Directory links appearing
-   * inside a path are followed, though, to find the file system object.
-   *
-   * Completes the returned Future with an error if one of the paths points
-   * to an object that does not exist.
-   */
+  /// Checks whether two paths refer to the same object in the
+  /// file system.
+  ///
+  /// Returns a `Future<bool>` that completes with the result.
+  ///
+  /// Comparing a link to its target returns `false`, as does comparing two links
+  /// that point to the same target.  To check the target of a link, use
+  /// Link.target explicitly to fetch it.  Directory links appearing
+  /// inside a path are followed, though, to find the file system object.
+  ///
+  /// Completes the returned Future with an error if one of the paths points
+  /// to an object that does not exist.
   static Future<bool> identical(String path1, String path2) {
     IOOverrides? overrides = IOOverrides.current;
     if (overrides == null) {
@@ -537,26 +486,24 @@
   static final RegExp _absoluteWindowsPathPattern =
       new RegExp(r'^(?:\\\\|[a-zA-Z]:[/\\])');
 
-  /**
-   * Whether this object's path is absolute.
-   *
-   * An absolute path is independent of the current working
-   * directory ([Directory.current]).
-   * A non-absolute path must be interpreted relative to
-   * the current working directory.
-   *
-   * On Windows, a path is absolute if it starts with `\\`
-   * (two backslashesor representing a UNC path) or with a drive letter
-   * between `a` and `z` (upper or lower case) followed by `:\` or `:/`.
-   * The makes, for example, `\file.ext` a non-absolute path
-   * because it depends on the current drive letter.
-   *
-   * On non-Windows, a path is absolute if it starts with `/`.
-   *
-   * If the path is not absolute, use [absolute] to get an entity
-   * with an absolute path referencing the same object in the file system,
-   * if possible.
-   */
+  /// Whether this object's path is absolute.
+  ///
+  /// An absolute path is independent of the current working
+  /// directory ([Directory.current]).
+  /// A non-absolute path must be interpreted relative to
+  /// the current working directory.
+  ///
+  /// On Windows, a path is absolute if it starts with `\\`
+  /// (two backslashesor representing a UNC path) or with a drive letter
+  /// between `a` and `z` (upper or lower case) followed by `:\` or `:/`.
+  /// The makes, for example, `\file.ext` a non-absolute path
+  /// because it depends on the current drive letter.
+  ///
+  /// On non-Windows, a path is absolute if it starts with `/`.
+  ///
+  /// If the path is not absolute, use [absolute] to get an entity
+  /// with an absolute path referencing the same object in the file system,
+  /// if possible.
   bool get isAbsolute => _isAbsolute(path);
 
   static bool _isAbsolute(String path) {
@@ -567,16 +514,15 @@
     }
   }
 
-  /**
-   * Returns a [FileSystemEntity] whose path is the absolute path to [this].
-   *
-   * The type of the returned instance is the type of [this].
-   *
-   * A file system entity with an already absolute path
-   * (as reported by [isAbsolute]) is returned directly.
-   * For a non-absolute path, the returned entity is absolute ([isAbsolute])
-   * *if possible*, but still refers to the same file system object.
-   */
+  /// A [FileSystemEntity] whose path is the absolute path of [path].
+  ///
+  /// The type of the returned instance is the same as the type of
+  /// this entity.
+  ///
+  /// A file system entity with an already absolute path
+  /// (as reported by [isAbsolute]) is returned directly.
+  /// For a non-absolute path, the returned entity is absolute ([isAbsolute])
+  /// *if possible*, but still refers to the same file system object.
   FileSystemEntity get absolute;
 
   String get _absolutePath {
@@ -590,10 +536,10 @@
     }
   }
 
-  /// The ASCII code of the Windows drive letter if [entity], if any.
+  /// The ASCII code of the Windows drive letter of [path], if any.
   ///
   /// Returns the ASCII code of the upper-cased drive letter of
-  /// the path of [entity], if it has a drive letter (starts with `[a-zA-z]:`),
+  /// the path of [path], if it has a drive letter (starts with `[a-zA-z]:`),
   /// or `-1` if it has no drive letter.
   static int _windowsDriveLetter(String path) {
     if (path.isEmpty || !path.startsWith(':', 1)) return -1;
@@ -661,18 +607,16 @@
     return result;
   }
 
-  /**
-   * Synchronously checks whether two paths refer to the same object in the
-   * file system.
-   *
-   * Comparing a link to its target returns false, as does comparing two links
-   * that point to the same target.  To check the target of a link, use
-   * Link.target explicitly to fetch it.  Directory links appearing
-   * inside a path are followed, though, to find the file system object.
-   *
-   * Throws an error if one of the paths points to an object that does not
-   * exist.
-   */
+  /// Synchronously checks whether two paths refer to the same object in the
+  /// file system.
+  ///
+  /// Comparing a link to its target returns `false`, as does comparing two links
+  /// that point to the same target.  To check the target of a link, use
+  /// Link.target explicitly to fetch it.  Directory links appearing
+  /// inside a path are followed, though, to find the file system object.
+  ///
+  /// Throws an error if one of the paths points to an object that does not
+  /// exist.
   static bool identicalSync(String path1, String path2) {
     IOOverrides? overrides = IOOverrides.current;
     if (overrides == null) {
@@ -681,11 +625,9 @@
     return overrides.fseIdenticalSync(path1, path2);
   }
 
-  /**
-   * Test if [watch] is supported on the current system.
-   *
-   * OS X 10.6 and below is not supported.
-   */
+  /// Test if [watch] is supported on the current system.
+  ///
+  /// OS X 10.6 and below is not supported.
   static bool get isWatchSupported {
     final IOOverrides? overrides = IOOverrides.current;
     if (overrides == null) {
@@ -718,73 +660,68 @@
     return utf8.decode(nonNullTerminated, allowMalformed: true);
   }
 
-  /**
-   * Finds the type of file system object that a path points to.
-   *
-   * Returns a [:Future<FileSystemEntityType>:] that completes with the same
-   * results as [typeSync].
-   */
+  /// Finds the type of file system object that a path points to.
+  ///
+  /// Returns a `Future<FileSystemEntityType>` that completes with the same
+  /// results as [typeSync].
   static Future<FileSystemEntityType> type(String path,
-      {bool followLinks: true}) {
+      {bool followLinks = true}) {
     return _getType(_toUtf8Array(path), followLinks);
   }
 
-  /**
-   * Synchronously finds the type of file system object that a path points to.
-   *
-   * Returns a [FileSystemEntityType].
-   *
-   * Returns [FileSystemEntityType.link] only if [followLinks] is false and if
-   * [path] points to a link.
-   *
-   * Returns [FileSystemEntityType.notFound] if [path] does not point to a file
-   * system object or if any other error occurs in looking up the path.
-   */
-  static FileSystemEntityType typeSync(String path, {bool followLinks: true}) {
+  /// Synchronously finds the type of file system object that a path points to.
+  ///
+  /// Returns [FileSystemEntityType.link] only if [followLinks] is `false` and if
+  /// [path] points to a link.
+  ///
+  /// Returns [FileSystemEntityType.notFound] if [path] does not point to a file
+  /// system object or if any other error occurs in looking up the path.
+  static FileSystemEntityType typeSync(String path, {bool followLinks = true}) {
     return _getTypeSync(_toUtf8Array(path), followLinks);
   }
 
-  /**
-   * Checks if type(path, followLinks: false) returns FileSystemEntityType.link.
-   */
+  /// Whether [path] refers to a link.
+  ///
+  /// Checks whether `type(path, followLinks: false)`
+  /// returns [FileSystemEntityType.link].
   static Future<bool> isLink(String path) => _isLinkRaw(_toUtf8Array(path));
 
   static Future<bool> _isLinkRaw(Uint8List rawPath) => _getType(rawPath, false)
       .then((type) => (type == FileSystemEntityType.link));
 
-  /**
-   * Checks if type(path) returns FileSystemEntityType.file.
-   */
+  /// Whether [path] refers to a file.
+  ///
+  /// Checks whether `type(path)` returns [FileSystemEntityType.file].
   static Future<bool> isFile(String path) => _getType(_toUtf8Array(path), true)
       .then((type) => (type == FileSystemEntityType.file));
 
-  /**
-   * Checks if type(path) returns FileSystemEntityType.directory.
-   */
+  /// Whether [path]] refers to a directory.
+  ///
+  /// Checks whether `type(path)` returns [FileSystemEntityType.directory].
   static Future<bool> isDirectory(String path) =>
       _getType(_toUtf8Array(path), true)
           .then((type) => (type == FileSystemEntityType.directory));
 
-  /**
-   * Synchronously checks if typeSync(path, followLinks: false) returns
-   * FileSystemEntityType.link.
-   */
+  /// Synchronously checks whether [path] refers to a link.
+  ///
+  /// Checks whether `typeSync(path, followLinks: false)` returns
+  /// [FileSystemEntityType.link].
   static bool isLinkSync(String path) => _isLinkRawSync(_toUtf8Array(path));
 
   static bool _isLinkRawSync(rawPath) =>
       (_getTypeSync(rawPath, false) == FileSystemEntityType.link);
 
-  /**
-   * Synchronously checks if typeSync(path) returns
-   * FileSystemEntityType.file.
-   */
+  /// Synchronously checks whether [path] refers to a file.
+  ///
+  /// Checks whether `typeSync(path)` returns
+  /// [FileSystemEntityType.file].
   static bool isFileSync(String path) =>
       (_getTypeSync(_toUtf8Array(path), true) == FileSystemEntityType.file);
 
-  /**
-   * Synchronously checks if typeSync(path) returns
-   * FileSystemEntityType.directory.
-   */
+  /// Synchronously checks whether [path] refers to a directory.
+  ///
+  /// Checks whether `typeSync(path)` returns
+  /// [FileSystemEntityType.directory].
   static bool isDirectorySync(String path) =>
       (_getTypeSync(_toUtf8Array(path), true) ==
           FileSystemEntityType.directory);
@@ -800,14 +737,15 @@
       ? new RegExp(r'[^/\\][/\\]+[^/\\]')
       : new RegExp(r'[^/]/+[^/]');
 
-  /**
-   * Removes the final path component of a path, using the platform's
-   * path separator to split the path.
-   *
-   * Will not remove the root component of a Windows path, like "C:\\" or
-   * "\\\\server_name\\". Ignores trailing path separators, and leaves no
-   * trailing path separators.
-   */
+  /// The parent path of a path.
+  ///
+  /// Finds the final path component of a path, using the platform's
+  /// path separator to split the path, and returns the prefix up to
+  /// that part.
+  ///
+  /// Will not remove the root component of a Windows path, like "C:\\" or
+  /// "\\\\server_name\\". Includes a trailing path separator in the last
+  /// part of [path], and leaves no trailing path separator.
   static String parentOf(String path) {
     int rootEnd = -1;
     if (Platform.isWindows) {
@@ -833,9 +771,7 @@
     }
   }
 
-  /**
-   * The directory containing [this].
-   */
+  /// The parent directory of this entity.
   Directory get parent => new Directory(parentOf(path));
 
   static FileSystemEntityType _getTypeSyncHelper(
@@ -918,42 +854,30 @@
   }
 }
 
-/**
- * Base event class emitted by [FileSystemEntity.watch].
- */
+/// Base event class emitted by [FileSystemEntity.watch].
 class FileSystemEvent {
-  /**
-   * Bitfield for [FileSystemEntity.watch], to enable [FileSystemCreateEvent]s.
-   */
+  /// Bitfield for [FileSystemEntity.watch], to enable [FileSystemCreateEvent]s.
   static const int create = 1 << 0;
   @Deprecated("Use create instead")
   static const int CREATE = 1 << 0;
 
-  /**
-   * Bitfield for [FileSystemEntity.watch], to enable [FileSystemModifyEvent]s.
-   */
+  /// Bitfield for [FileSystemEntity.watch], to enable [FileSystemModifyEvent]s.
   static const int modify = 1 << 1;
   @Deprecated("Use modify instead")
   static const int MODIFY = 1 << 1;
 
-  /**
-   * Bitfield for [FileSystemEntity.watch], to enable [FileSystemDeleteEvent]s.
-   */
+  /// Bitfield for [FileSystemEntity.watch], to enable [FileSystemDeleteEvent]s.
   static const int delete = 1 << 2;
   @Deprecated("Use delete instead")
   static const int DELETE = 1 << 2;
 
-  /**
-   * Bitfield for [FileSystemEntity.watch], to enable [FileSystemMoveEvent]s.
-   */
+  /// Bitfield for [FileSystemEntity.watch], to enable [FileSystemMoveEvent]s.
   static const int move = 1 << 3;
   @Deprecated("Use move instead")
   static const int MOVE = 1 << 3;
 
-  /**
-   * Bitfield for [FileSystemEntity.watch], for enabling all of [create],
-   * [modify], [delete] and [move].
-   */
+  /// Bitfield for [FileSystemEntity.watch], for enabling all of [create],
+  /// [modify], [delete] and [move].
   static const int all = create | modify | delete | move;
   @Deprecated("Use all instead")
   static const int ALL = create | modify | delete | move;
@@ -962,34 +886,26 @@
   static const int _deleteSelf = 1 << 5;
   static const int _isDir = 1 << 6;
 
-  /**
-   * The type of event. See [FileSystemEvent] for a list of events.
-   */
+  /// The type of event. See [FileSystemEvent] for a list of events.
   final int type;
 
-  /**
-   * The path that triggered the event.
-   *
-   * Depending on the platform and the FileSystemEntity, the path may be
-   * relative.
-   */
+  /// The path that triggered the event.
+  ///
+  /// Depending on the platform and the [FileSystemEntity], the path may be
+  /// relative.
   final String path;
 
-  /**
-   * Is `true` if the event target was a directory.
-   *
-   * Note that if the file has been deleted by the time the event has arrived,
-   * this will always be `false` on Windows. In particular, it will always be
-   * `false` for `delete` events.
-   */
+  /// Is `true` if the event target was a directory.
+  ///
+  /// Note that if the file has been deleted by the time the event has arrived,
+  /// this will always be `false` on Windows. In particular, it will always be
+  /// `false` for `delete` events.
   final bool isDirectory;
 
   FileSystemEvent._(this.type, this.path, this.isDirectory);
 }
 
-/**
- * File system event for newly created file system objects.
- */
+/// File system event for newly created file system objects.
 class FileSystemCreateEvent extends FileSystemEvent {
   FileSystemCreateEvent._(path, isDirectory)
       : super._(FileSystemEvent.create, path, isDirectory);
@@ -997,14 +913,10 @@
   String toString() => "FileSystemCreateEvent('$path')";
 }
 
-/**
- * File system event for modifications of file system objects.
- */
+/// File system event for modifications of file system objects.
 class FileSystemModifyEvent extends FileSystemEvent {
-  /**
-   * If the content was changed and not only the attributes, [contentChanged]
-   * is `true`.
-   */
+  /// If the content was changed and not only the attributes, [contentChanged]
+  /// is `true`.
   final bool contentChanged;
 
   FileSystemModifyEvent._(path, isDirectory, this.contentChanged)
@@ -1014,9 +926,7 @@
       "FileSystemModifyEvent('$path', contentChanged=$contentChanged)";
 }
 
-/**
- * File system event for deletion of file system objects.
- */
+/// File system event for deletion of file system objects.
 class FileSystemDeleteEvent extends FileSystemEvent {
   FileSystemDeleteEvent._(path, isDirectory)
       : super._(FileSystemEvent.delete, path, isDirectory);
@@ -1024,14 +934,14 @@
   String toString() => "FileSystemDeleteEvent('$path')";
 }
 
-/**
- * File system event for moving of file system objects.
- */
+/// File system event for moving of file system objects.
 class FileSystemMoveEvent extends FileSystemEvent {
-  /**
-   * If the underlying implementation is able to identify the destination of
-   * the moved file, [destination] will be set. Otherwise, it will be `null`.
-   */
+  /// The destination path of the file being moved.
+  ///
+  /// The destination is `null` if the underlying implementation
+  /// is unable to identify the destination of the moved file.
+  ///
+  /// The source path is available as [path].
   final String? destination;
 
   FileSystemMoveEvent._(path, isDirectory, this.destination)
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index cabba39..5be8785 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -2,190 +2,191 @@
 // 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.
 
-/**
- * File, socket, HTTP, and other I/O support for non-web applications.
- *
- * **Important:** Browser-based apps can't use this library.
- * Only the following can import and use the dart:io library:
- *   - Servers
- *   - Command-line scripts
- *   - Flutter mobile apps
- *   - Flutter desktop apps
- *
- * This library allows you to work with files, directories,
- * sockets, processes, HTTP servers and clients, and more.
- * Many operations related to input and output are asynchronous
- * and are handled using [Future]s or [Stream]s, both of which
- * are defined in the [dart:async
- * library](../dart-async/dart-async-library.html).
- *
- * To use the dart:io library in your code:
- *
- *     import 'dart:io';
- *
- * For an introduction to I/O in Dart, see the [dart:io library
- * tour](https://dart.dev/guides/libraries/library-tour#dartio).
- *
- * ## File, Directory, and Link
- *
- * An instance of [File], [Directory], or [Link] represents a file,
- * directory, or link, respectively, in the native file system.
- *
- * You can manipulate the file system through objects of these types.
- * For example, you can rename a file or directory:
- *
- *     File myFile = new File('myFile.txt');
- *     myFile.rename('yourFile.txt').then((_) => print('file renamed'));
- *
- * Many methods provided by the File, Directory, and Link classes
- * run asynchronously and return a Future.
- *
- * ## FileSystemEntity
- *
- * File, Directory, and Link all extend [FileSystemEntity].
- * In addition to being the superclass for these classes,
- * FileSystemEntity has a number of static methods for working with paths.
- *
- * To get information about a path,
- * you can use the FileSystemEntity static methods
- * such as 'isDirectory', 'isFile', and 'exists'.
- * Because file system access involves I/O, these methods
- * are asynchronous and return a Future.
- *
- *     FileSystemEntity.isDirectory(myPath).then((isDir) {
- *       if (isDir) {
- *         print('$myPath is a directory');
- *       } else {
- *         print('$myPath is not a directory');
- *       }
- *     });
- *
- * ## HttpServer and HttpClient
- *
- * The classes [HttpServer] and [HttpClient]
- * provide HTTP server and HTTP client functionality.
- *
- * The [HttpServer] class provides the basic functionality for
- * implementing an HTTP server.
- * For some higher-level building-blocks, we recommend that you try
- * the [shelf](https://pub.dev/packages/shelf)
- * pub package, which contains
- * a set of high-level classes that, together with the [HttpServer] class
- * in this library, make it easier to implement HTTP servers.
- *
- * ## Process
- *
- * The [Process] class provides a way to run a process on
- * the native machine.
- * For example, the following code spawns a process that recursively lists
- * the files under `web`.
- *
- *     Process.start('ls', ['-R', 'web']).then((process) {
- *       stdout.addStream(process.stdout);
- *       stderr.addStream(process.stderr);
- *       process.exitCode.then(print);
- *     });
- *
- * Using `start()` returns a Future, which completes with a [Process] object
- * when the process has started. This [Process] object allows you to interact
- * with the process while it is running. Using `run()` returns a Future, which
- * completes with a [ProcessResult] object when the spawned process has
- * terminated. This [ProcessResult] object collects the output and exit code
- * from the process.
- *
- * When using `start()`,
- * you need to read all data coming on the stdout and stderr streams otherwise
- * the system resources will not be freed.
- *
- * ## WebSocket
- *
- * The [WebSocket] class provides support for the web socket protocol. This
- * allows full-duplex communications between client and server applications.
- *
- * A web socket server uses a normal HTTP server for accepting web socket
- * connections. The initial handshake is a HTTP request which is then upgraded to a
- * web socket connection.
- * The server upgrades the request using [WebSocketTransformer]
- * and listens for the data on the returned web socket.
- * For example, here's a mini server that listens for 'ws' data
- * on a WebSocket:
- *
- *     runZoned(() async {
- *       var server = await HttpServer.bind('127.0.0.1', 4040);
- *       server.listen((HttpRequest req) async {
- *         if (req.uri.path == '/ws') {
- *           var socket = await WebSocketTransformer.upgrade(req);
- *           socket.listen(handleMsg);
- *         }
- *       });
- *     }, onError: (e) => print("An error occurred."));
- *
- * The client connects to the WebSocket using the `connect()` method
- * and a URI that uses the Web Socket protocol.
- * The client can write to the WebSocket with the `add()` method.
- * For example,
- *
- *     var socket = await WebSocket.connect('ws://127.0.0.1:4040/ws');
- *     socket.add('Hello, World!');
- *
- * Check out the
- * [websocket_sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/websockets/basics)
- * app, which uses WebSockets to communicate with a server.
- *
- * ## Socket and ServerSocket
- *
- * Clients and servers use [Socket]s to communicate using the TCP protocol.
- * Use [ServerSocket] on the server side and [Socket] on the client.
- * The server creates a listening socket using the `bind()` method and
- * then listens for incoming connections on the socket. For example:
- *
- *     ServerSocket.bind('127.0.0.1', 4041)
- *       .then((serverSocket) {
- *         serverSocket.listen((socket) {
- *           socket.transform(utf8.decoder).listen(print);
- *         });
- *       });
- *
- * A client connects a Socket using the `connect()` method,
- * which returns a Future.
- * Using `write()`, `writeln()`, or `writeAll()` are the easiest ways to
- * send data over the socket.
- * For example:
- *
- *     Socket.connect('127.0.0.1', 4041).then((socket) {
- *       socket.write('Hello, World!');
- *     });
- *
- * Besides [Socket] and [ServerSocket], the [RawSocket] and
- * [RawServerSocket] classes are available for lower-level access
- * to async socket IO.
- *
- * ## Standard output, error, and input streams
- *
- * This library provides the standard output, error, and input
- * streams, named 'stdout', 'stderr', and 'stdin', respectively.
- *
- * The stdout and stderr streams are both [IOSink]s and have the same set
- * of methods and properties.
- *
- * To write a string to 'stdout':
- *
- *     stdout.writeln('Hello, World!');
- *
- * To write a list of objects to 'stderr':
- *
- *     stderr.writeAll([ 'That ', 'is ', 'an ', 'error.', '\n']);
- *
- * The standard input stream is a true [Stream], so it inherits
- * properties and methods from the Stream class.
- *
- * To read text synchronously from the command line
- * (the program blocks waiting for user to type information):
- *
- *      String inputText = stdin.readLineSync();
- *
- * {@category VM}
- */
+/// File, socket, HTTP, and other I/O support for non-web applications.
+///
+/// **Important:** Browser-based apps can't use this library.
+/// Only the following can import and use the dart:io library:
+///   - Servers
+///   - Command-line scripts
+///   - Flutter mobile apps
+///   - Flutter desktop apps
+///
+/// This library allows you to work with files, directories,
+/// sockets, processes, HTTP servers and clients, and more.
+/// Many operations related to input and output are asynchronous
+/// and are handled using [Future]s or [Stream]s, both of which
+/// are defined in the [dart:async
+/// library](../dart-async/dart-async-library.html).
+///
+/// To use the dart:io library in your code:
+/// ```dart
+/// import 'dart:io';
+/// ```
+/// For an introduction to I/O in Dart, see the [dart:io library
+/// tour](https://dart.dev/guides/libraries/library-tour#dartio).
+///
+/// ## File, Directory, and Link
+///
+/// An instance of [File], [Directory], or [Link] represents a file,
+/// directory, or link, respectively, in the native file system.
+///
+/// You can manipulate the file system through objects of these types.
+/// For example, you can rename a file or directory:
+/// ```dart
+/// File myFile = File('myFile.txt');
+/// myFile.rename('yourFile.txt').then((_) => print('file renamed'));
+/// ```
+/// Many methods provided by the [File], [Directory], and [Link] classes
+/// run asynchronously and return a [Future].
+///
+/// ## FileSystemEntity
+///
+/// [File], [Directory], and [Link] all extend [FileSystemEntity].
+/// In addition to being the superclass for these classes,
+/// FileSystemEntity has a number of static methods for working with paths.
+///
+/// To get information about a path,
+/// you can use the [FileSystemEntity] static methods
+/// such as [FileSystemEntitiy.isDirectory], [FileSystemEntitiy.isFile],
+/// and [FileSystemEntitiy.exists].
+/// Because file system access involves I/O, these methods
+/// are asynchronous and return a [Future].
+/// ```dart
+/// FileSystemEntity.isDirectory(myPath).then((isDir) {
+///   if (isDir) {
+///     print('$myPath is a directory');
+///   } else {
+///     print('$myPath is not a directory');
+///   }
+/// });
+/// ```
+/// ## HttpServer and HttpClient
+///
+/// The classes [HttpServer] and [HttpClient]
+/// provide HTTP server and HTTP client functionality.
+///
+/// The [HttpServer] class provides the basic functionality for
+/// implementing an HTTP server.
+/// For some higher-level building-blocks, we recommend that you try
+/// the [shelf](https://pub.dev/packages/shelf)
+/// pub package, which contains
+/// a set of high-level classes that, together with the [HttpServer] class
+/// in this library, make it easier to implement HTTP servers.
+///
+/// ## Process
+///
+/// The [Process] class provides a way to run a process on
+/// the native machine.
+/// For example, the following code spawns a process that recursively lists
+/// the files under `web`.
+/// ```dart
+/// Process.start('ls', ['-R', 'web']).then((process) {
+///   stdout.addStream(process.stdout);
+///   stderr.addStream(process.stderr);
+///   process.exitCode.then(print);
+/// });
+/// ```
+/// Using [Process.start] returns a [Future],
+/// which completes with a [Process] object when the process has started.
+/// This [Process] object allows you to interact
+/// with the process while it is running.
+/// Using [Process.run] returns a [Future],
+/// which completes with a [ProcessResult] object when the spawned process has
+/// terminated. This [ProcessResult] object collects the output and exit code
+/// from the process.
+///
+/// When using [Process.start],
+/// you need to read all data coming on the [Process.stdout] and [Process.stderr]
+/// streams, otherwise the system resources will not be freed.
+///
+/// ## WebSocket
+///
+/// The [WebSocket] class provides support for the web socket protocol. This
+/// allows full-duplex communications between client and server applications.
+///
+/// A web socket server uses a normal HTTP server for accepting web socket
+/// connections. The initial handshake is a HTTP request which is then upgraded to a
+/// web socket connection.
+/// The server upgrades the request using [WebSocketTransformer]
+/// and listens for the data on the returned web socket.
+/// For example, here's a mini server that listens for 'ws' data
+/// on a WebSocket:
+/// ```dart
+/// runZoned(() async {
+///   var server = await HttpServer.bind('127.0.0.1', 4040);
+///   server.listen((HttpRequest req) async {
+///     if (req.uri.path == '/ws') {
+///       var socket = await WebSocketTransformer.upgrade(req);
+///       socket.listen(handleMsg);
+///     }
+///   });
+/// }, onError: (e) => print("An error occurred."));
+/// ```
+/// The client connects to the [WebSocket] using the [WebSocket.connect] method
+/// and a URI that uses the Web Socket protocol.
+/// The client can write to the [WebSocket] with the [Websocket.add] method.
+/// For example,
+/// ```dart
+/// var socket = await WebSocket.connect('ws://127.0.0.1:4040/ws');
+/// socket.add('Hello, World!');
+/// ```
+/// Check out the
+/// [websocket_sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/websockets/basics)
+/// app, which uses [WebSocket]s to communicate with a server.
+///
+/// ## Socket and ServerSocket
+///
+/// Clients and servers use [Socket]s to communicate using the TCP protocol.
+/// Use [ServerSocket] on the server side and [Socket] on the client.
+/// The server creates a listening socket using the `bind()` method and
+/// then listens for incoming connections on the socket. For example:
+/// ```dart
+/// ServerSocket.bind('127.0.0.1', 4041)
+///   .then((serverSocket) {
+///     serverSocket.listen((socket) {
+///       socket.transform(utf8.decoder).listen(print);
+///     });
+///   });
+/// ```
+/// A client connects a [Socket] using the `connect()` method,
+/// which returns a [Future].
+/// Using `write()`, `writeln()`, or `writeAll()` are the easiest ways to
+/// send data over the socket.
+/// For example:
+/// ```dart
+/// Socket.connect('127.0.0.1', 4041).then((socket) {
+///   socket.write('Hello, World!');
+/// });
+/// ```
+/// Besides [Socket] and [ServerSocket], the [RawSocket] and
+/// [RawServerSocket] classes are available for lower-level access
+/// to async socket IO.
+///
+/// ## Standard output, error, and input streams
+///
+/// This library provides the standard output, error, and input
+/// streams, named [stdout], [stderr], and [stdin], respectively.
+///
+/// The [stdout] and [stderr] streams are both [IOSink]s and have the same set
+/// of methods and properties.
+///
+/// To write a string to [stdout]:
+/// ```dart
+/// stdout.writeln('Hello, World!');
+/// ```
+/// To write a list of objects to [stderr]:
+/// ```dart
+/// stderr.writeAll([ 'That ', 'is ', 'an ', 'error.', '\n']);
+/// ```
+/// The standard input stream is a true [Stream], so it inherits
+/// properties and methods from the [Stream] class.
+///
+/// To read text synchronously from the command line
+/// (the program blocks waiting for user to type information):
+/// ```dart
+/// String inputText = stdin.readLineSync();
+/// ```
+/// {@category VM}
 library dart.io;
 
 import 'dart:async';
diff --git a/sdk/lib/io/io_sink.dart b/sdk/lib/io/io_sink.dart
index 622656a..60de5da 100644
--- a/sdk/lib/io/io_sink.dart
+++ b/sdk/lib/io/io_sink.dart
@@ -4,137 +4,117 @@
 
 part of dart.io;
 
-/**
- * A combined byte and text output.
- *
- * An [IOSink] combines a [StreamSink] of bytes with a [StringSink],
- * and allows easy output of both bytes and text.
- *
- * Writing text ([write]) and adding bytes ([add]) may be interleaved freely.
- *
- * While a stream is being added using [addStream], any further attempts
- * to add or write to the [IOSink] will fail until the [addStream] completes.
- *
- * It is an error to add data to the [IOSink] after the sink is closed.
- */
+/// A combined byte and text output.
+///
+/// An [IOSink] combines a [StreamSink] of bytes with a [StringSink],
+/// and allows easy output of both bytes and text.
+///
+/// Writing text ([write]) and adding bytes ([add]) may be interleaved freely.
+///
+/// While a stream is being added using [addStream], any further attempts
+/// to add or write to the [IOSink] will fail until the [addStream] completes.
+///
+/// It is an error to add data to the [IOSink] after the sink is closed.
 abstract class IOSink implements StreamSink<List<int>>, StringSink {
-  /**
-   * Create an [IOSink] that outputs to a [target] [StreamConsumer] of bytes.
-   *
-   * Text written to [StreamSink] methods is encoded to bytes using [encoding]
-   * before being output on [target].
-   */
-  factory IOSink(StreamConsumer<List<int>> target, {Encoding encoding: utf8}) =>
+  /// Create an [IOSink] that outputs to a [target] [StreamConsumer] of bytes.
+  ///
+  /// Text written to [StreamSink] methods is encoded to bytes using [encoding]
+  /// before being output on [target].
+  factory IOSink(StreamConsumer<List<int>> target,
+          {Encoding encoding = utf8}) =>
       new _IOSinkImpl(target, encoding);
 
-  /**
-   * The [Encoding] used when writing strings. Depending on the
-   * underlying consumer this property might be mutable.
-   */
+  /// The [Encoding] used when writing strings.
+  ///
+  /// Depending on the underlying consumer, this property might be mutable.
   late Encoding encoding;
 
-  /**
-   * Adds byte [data] to the target consumer, ignoring [encoding].
-   *
-   * The [encoding] does not apply to this method, and the `data` list is passed
-   * directly to the target consumer as a stream event.
-   *
-   * This function must not be called when a stream is currently being added
-   * using [addStream].
-   *
-   * This operation is non-blocking. See [flush] or [done] for how to get any
-   * errors generated by this call.
-   *
-   * The data list should not be modified after it has been passed to `add`.
-   */
+  /// Adds byte [data] to the target consumer, ignoring [encoding].
+  ///
+  /// The [encoding] does not apply to this method, and the [data] list is passed
+  /// directly to the target consumer as a stream event.
+  ///
+  /// This function must not be called when a stream is currently being added
+  /// using [addStream].
+  ///
+  /// This operation is non-blocking. See [flush] or [done] for how to get any
+  /// errors generated by this call.
+  ///
+  /// The data list should not be modified after it has been passed to `add`.
   void add(List<int> data);
 
-  /**
-   * Converts [obj] to a String by invoking [Object.toString] and
-   * [add]s the encoding of the result to the target consumer.
-   *
-   * This operation is non-blocking. See [flush] or [done] for how to get any
-   * errors generated by this call.
-   */
-  void write(Object? obj);
+  /// Converts [object] to a String by invoking [Object.toString] and
+  /// [add]s the encoding of the result to the target consumer.
+  ///
+  /// This operation is non-blocking. See [flush] or [done] for how to get any
+  /// errors generated by this call.
+  void write(Object? object);
 
-  /**
-   * Iterates over the given [objects] and [write]s them in sequence.
-   *
-   * If [separator] is provided, a `write` with the `separator` is performed
-   * between any two elements of objects.
-   *
-   * This operation is non-blocking. See [flush] or [done] for how to get any
-   * errors generated by this call.
-   */
+  /// Iterates over the given [objects] and [write]s them in sequence.
+  ///
+  /// If [separator] is provided, a `write` with the `separator` is performed
+  /// between any two elements of objects.
+  ///
+  /// This operation is non-blocking. See [flush] or [done] for how to get any
+  /// errors generated by this call.
   void writeAll(Iterable objects, [String separator = ""]);
 
-  /**
-   * Converts [obj] to a String by invoking [Object.toString] and
-   * writes the result to `this`, followed by a newline.
-   *
-   * This operation is non-blocking. See [flush] or [done] for how to get any
-   * errors generated by this call.
-   */
-  void writeln([Object? obj = ""]);
+  /// Converts [object] to a String by invoking [Object.toString] and
+  /// writes the result to `this`, followed by a newline.
+  ///
+  /// This operation is non-blocking. See [flush] or [done] for how to get any
+  /// errors generated by this call.
+  void writeln([Object? object = ""]);
 
-  /**
-   * Writes the character of [charCode].
-   *
-   * This method is equivalent to `write(new String.fromCharCode(charCode))`.
-   *
-   * This operation is non-blocking. See [flush] or [done] for how to get any
-   * errors generated by this call.
-   */
+  /// Writes the character of [charCode].
+  ///
+  /// This method is equivalent to `write(String.fromCharCode(charCode))`.
+  ///
+  /// This operation is non-blocking. See [flush] or [done] for how to get any
+  /// errors generated by this call.
   void writeCharCode(int charCode);
 
-  /**
-   * Passes the error to the target consumer as an error event.
-   *
-   * This function must not be called when a stream is currently being added
-   * using [addStream].
-   *
-   * This operation is non-blocking. See [flush] or [done] for how to get any
-   * errors generated by this call.
-   */
+  /// Passes the error to the target consumer as an error event.
+  ///
+  /// This function must not be called when a stream is currently being added
+  /// using [addStream].
+  ///
+  /// This operation is non-blocking. See [flush] or [done] for how to get any
+  /// errors generated by this call.
   void addError(error, [StackTrace? stackTrace]);
 
-  /**
-   * Adds all elements of the given [stream] to `this`.
-   *
-   * Returns a [Future] that completes when
-   * all elements of the given [stream] are added to `this`.
-   *
-   * This function must not be called when a stream is currently being added
-   * using this function.
-   */
+  /// Adds all elements of the given [stream].
+  ///
+  /// Returns a [Future] that completes when
+  /// all elements of the given [stream] have been added.
+  ///
+  /// If the stream contains an error, the `addStream` ends at the error,
+  /// and the returned future completes with that error.
+  ///
+  /// This function must not be called when a stream is currently being added
+  /// using this function.
   Future addStream(Stream<List<int>> stream);
 
-  /**
-   * Returns a [Future] that completes once all buffered data is accepted by the
-   * underlying [StreamConsumer].
-   *
-   * This method must not be called while an [addStream] is incomplete.
-   *
-   * NOTE: This is not necessarily the same as the data being flushed by the
-   * operating system.
-   */
+  /// Returns a [Future] that completes once all buffered data is accepted by the
+  /// underlying [StreamConsumer].
+  ///
+  /// This method must not be called while an [addStream] is incomplete.
+  ///
+  /// NOTE: This is not necessarily the same as the data being flushed by the
+  /// operating system.
   Future flush();
 
-  /**
-   * Close the target consumer.
-   *
-   * NOTE: Writes to the [IOSink] may be buffered, and may not be flushed by
-   * a call to `close()`. To flush all buffered writes, call `flush()` before
-   * calling `close()`.
-   */
+  /// Close the target consumer.
+  ///
+  /// NOTE: Writes to the [IOSink] may be buffered, and may not be flushed by
+  /// a call to `close()`. To flush all buffered writes, call `flush()` before
+  /// calling `close()`.
   Future close();
 
-  /**
-   * Get a future that will complete when the consumer closes, or when an
-   * error occurs. This future is identical to the future returned by
-   * [close].
-   */
+  /// A future that will complete when the consumer closes, or when an
+  /// error occurs.
+  ///
+  /// This future is identical to the future returned by [close].
   Future get done;
 }
 
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index ce50a4e..c7320ea 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.dart
@@ -4,15 +4,10 @@
 
 part of dart.io;
 
-/**
- * [Link] objects are references to filesystem links.
- *
- */
+/// References to filesystem links.
 @pragma("vm:entry-point")
 abstract class Link implements FileSystemEntity {
-  /**
-   * Creates a Link object.
-   */
+  /// Creates a Link object.
   @pragma("vm:entry-point")
   factory Link(String path) {
     final IOOverrides? overrides = IOOverrides.current;
@@ -28,127 +23,119 @@
     return new _Link.fromRawPath(rawPath);
   }
 
-  /**
-   * Creates a [Link] object.
-   *
-   * If [path] is a relative path, it will be interpreted relative to the
-   * current working directory (see [Directory.current]), when used.
-   *
-   * If [path] is an absolute path, it will be immune to changes to the
-   * current working directory.
-   */
+  /// Creates a [Link] object.
+  ///
+  /// If [path] is a relative path, it will be interpreted relative to the
+  /// current working directory (see [Directory.current]), when used.
+  ///
+  /// If [path] is an absolute path, it will be immune to changes to the
+  /// current working directory.
   factory Link.fromUri(Uri uri) => new Link(uri.toFilePath());
 
-  /**
-   * Creates a symbolic link. Returns a [:Future<Link>:] that completes with
-   * the link when it has been created. If the link exists,
-   * the future will complete with an error.
-   *
-   * If [recursive] is false, the default, the link is created
-   * only if all directories in its path exist.
-   * If [recursive] is true, all non-existing path
-   * components are created. The directories in the path of [target] are
-   * not affected, unless they are also in [path].
-   *
-   * On the Windows platform, this call will create a true symbolic link
-   * instead of a Junction. In order to create a symbolic link on Windows, Dart
-   * must be run in Administrator mode or the system must have Developer Mode
-   * enabled, otherwise a [FileSystemException] will be raised with
-   * `ERROR_PRIVILEGE_NOT_HELD` set as the errno when this call is made.
-   *
-   * On other platforms, the posix symlink() call is used to make a symbolic
-   * link containing the string [target].  If [target] is a relative path,
-   * it will be interpreted relative to the directory containing the link.
-   */
-  Future<Link> create(String target, {bool recursive: false});
+  /// Creates a symbolic link in the file system.
+  ///
+  /// Returns a `Future<Link>` that completes with
+  /// the link when it has been created. If the link path already exists,
+  /// the future will complete with an error.
+  ///
+  /// If [recursive] is `false`, the default, the link is created
+  /// only if all directories in its path exist.
+  /// If [recursive] is `true`, all non-existing parent paths
+  /// are created first. The directories in the path of [target] are
+  /// not affected, unless they are also in [path].
+  ///
+  /// On the Windows platform, this call will create a true symbolic link
+  /// instead of a Junction. In order to create a symbolic link on Windows, Dart
+  /// must be run in Administrator mode or the system must have Developer Mode
+  /// enabled, otherwise a [FileSystemException] will be raised with
+  /// `ERROR_PRIVILEGE_NOT_HELD` set as the errno when this call is made.
+  ///
+  /// On other platforms, the POSIX `symlink()` call is used to make a symbolic
+  /// link containing the string [target]. If [target] is a relative path,
+  /// it will be interpreted relative to the directory containing the link.
+  Future<Link> create(String target, {bool recursive = false});
 
-  /**
-   * Synchronously create the link. Calling [createSync] on an existing link
-   * will throw an exception.
-   *
-   * If [recursive] is false, the default, the link is created only if all
-   * directories in its path exist. If [recursive] is true, all
-   * non-existing path components are created. The directories in
-   * the path of [target] are not affected, unless they are also in [path].
-   *
-   * On the Windows platform, this call will create a true symbolic link
-   * instead of a Junction. In order to create a symbolic link on Windows, Dart
-   * must be run in Administrator mode or the system must have Developer Mode
-   * enabled, otherwise a [FileSystemException] will be raised with
-   * `ERROR_PRIVILEGE_NOT_HELD` set as the errno when this call is made.
-   *
-   * On other platforms, the posix symlink() call is used to make a symbolic
-   * link containing the string [target].  If [target] is a relative path,
-   * it will be interpreted relative to the directory containing the link.
-   */
-  void createSync(String target, {bool recursive: false});
+  /// Synchronously create the link. Calling [createSync] on an existing link
+  /// will throw an exception.
+  ///
+  /// If [recursive] is `false`, the default, the link is created only if all
+  /// directories in its path exist. If [recursive] is `true`, all
+  /// non-existing parent paths are created first. The directories in
+  /// the path of [target] are not affected, unless they are also in [path].
+  ///
+  /// On the Windows platform, this call will create a true symbolic link
+  /// instead of a Junction. In order to create a symbolic link on Windows, Dart
+  /// must be run in Administrator mode or the system must have Developer Mode
+  /// enabled, otherwise a [FileSystemException] will be raised with
+  /// `ERROR_PRIVILEGE_NOT_HELD` set as the errno when this call is made.
+  ///
+  /// On other platforms, the POSIX `symlink()` call is used to make a symbolic
+  /// link containing the string [target]. If [target] is a relative path,
+  /// it will be interpreted relative to the directory containing the link.
+  void createSync(String target, {bool recursive = false});
 
-  /**
-   * Synchronously updates the link. Calling [updateSync] on a non-existing link
-   * will throw an exception.
-   */
+  /// Synchronously updates the link.
+  ///
+  /// Calling [updateSync] on a non-existing link will throw an exception.
   void updateSync(String target);
 
-  /**
-   * Updates the link. Returns a [:Future<Link>:] that completes with the
-   * link when it has been updated.  Calling [update] on a non-existing link
-   * will complete its returned future with an exception.
-   */
+  /// Updates the link.
+  ///
+  /// Returns a `Future<Link>` that completes with the
+  /// link when it has been updated. Calling [update] on a non-existing link
+  /// will complete its returned future with an exception.
   Future<Link> update(String target);
 
   Future<String> resolveSymbolicLinks();
 
   String resolveSymbolicLinksSync();
 
-  /**
-   * Renames this link. Returns a `Future<Link>` that completes
-   * with a [Link] instance for the renamed link.
-   *
-   * If [newPath] identifies an existing link, that link is
-   * replaced. If [newPath] identifies an existing file or directory,
-   * the operation fails and the future completes with an exception.
-   */
+  /// Renames this link.
+  ///
+  /// Returns a `Future<Link>` that completes with a [Link]
+  /// for the renamed link.
+  ///
+  /// If [newPath] identifies an existing link, that link is
+  /// removed first. If [newPath] identifies an existing file or directory,
+  /// the operation fails and the future completes with an exception.
   Future<Link> rename(String newPath);
 
-  /**
-   * Synchronously renames this link. Returns a [Link]
-   * instance for the renamed link.
-   *
-   * If [newPath] identifies an existing link, that link is
-   * replaced. If [newPath] identifies an existing file or directory
-   * the operation fails and an exception is thrown.
-   */
+  /// Synchronously renames this link.
+  ///
+  /// Returns a [Link] instance for the renamed link.
+  ///
+  /// If [newPath] identifies an existing link, that link is
+  /// removed first. If [newPath] identifies an existing file or directory
+  /// the operation fails and an exception is thrown.
   Link renameSync(String newPath);
 
-  /**
-   * Returns a [Link] instance whose path is the absolute path to [this].
-   *
-   * The absolute path is computed by prefixing
-   * a relative path with the current working directory, and returning
-   * an absolute path unchanged.
-   */
+  /// A [Link] instance whose path is the absolute path to [this].
+  ///
+  /// The absolute path is computed by prefixing
+  /// a relative path with the current working directory, or returning
+  /// an absolute path unchanged.
   Link get absolute;
 
-  /**
-   * Gets the target of the link. Returns a future that completes with
-   * the path to the target.
-   *
-   * If the returned target is a relative path, it is relative to the
-   * directory containing the link.
-   *
-   * If the link does not exist, or is not a link, the future completes with
-   * a FileSystemException.
-   */
+  /// Gets the target of the link.
+  ///
+  /// Returns a future that completes with the path to the target.
+  ///
+  /// If the returned target is a relative path, it is relative to the
+  /// directory containing the link.
+  ///
+  /// If the link does not exist, or is not a link, the future completes with
+  /// a [FileSystemException].
   Future<String> target();
 
-  /**
-   * Synchronously gets the target of the link. Returns the path to the target.
-   *
-   * If the returned target is a relative path, it is relative to the
-   * directory containing the link.
-   *
-   * If the link does not exist, or is not a link, throws a FileSystemException.
-   */
+  /// Synchronously gets the target of the link.
+  ///
+  /// Returns the path to the target.
+  ///
+  /// If the returned target is a relative path, it is relative to the
+  /// directory containing the link.
+  ///
+  /// If the link does not exist, or is not a link,
+  /// throws a [FileSystemException].
   String targetSync();
 }
 
@@ -174,7 +161,7 @@
 
   Link get absolute => isAbsolute ? this : _Link(_absolutePath);
 
-  Future<Link> create(String target, {bool recursive: false}) {
+  Future<Link> create(String target, {bool recursive = false}) {
     var result =
         recursive ? parent.create(recursive: true) : new Future.value(null);
     return result
@@ -189,7 +176,7 @@
     });
   }
 
-  void createSync(String target, {bool recursive: false}) {
+  void createSync(String target, {bool recursive = false}) {
     if (recursive) {
       parent.createSync(recursive: true);
     }
@@ -214,7 +201,7 @@
     return delete().then<Link>((_) => create(target));
   }
 
-  Future<Link> _delete({bool recursive: false}) {
+  Future<Link> _delete({bool recursive = false}) {
     if (recursive) {
       return new Directory.fromRawPath(_rawPath)
           .delete(recursive: true)
@@ -229,7 +216,7 @@
     });
   }
 
-  void _deleteSync({bool recursive: false}) {
+  void _deleteSync({bool recursive = false}) {
     if (recursive) {
       return new Directory.fromRawPath(_rawPath).deleteSync(recursive: true);
     }
diff --git a/sdk/lib/io/overrides.dart b/sdk/lib/io/overrides.dart
index 4b7deaa..245b9d7 100644
--- a/sdk/lib/io/overrides.dart
+++ b/sdk/lib/io/overrides.dart
@@ -8,12 +8,12 @@
 
 const _asyncRunZoned = runZoned;
 
-/// This class facilitates overriding various APIs of dart:io with mock
+/// Facilities for overriding various APIs of `dart:io` with mock
 /// implementations.
 ///
 /// This abstract base class should be extended with overrides for the
 /// operations needed to construct mocks. The implementations in this base class
-/// default to the actual dart:io implementation. For example:
+/// default to the actual `dart:io` implementation. For example:
 ///
 /// ```
 /// class MyDirectory implements Directory {
@@ -22,7 +22,7 @@
 ///   ...
 /// }
 ///
-/// main() {
+/// void main() {
 ///   IOOverrides.runZoned(() {
 ///     ...
 ///     // Operations will use MyDirectory instead of dart:io's Directory
@@ -40,16 +40,16 @@
 
   /// The [IOOverrides] to use in the root [Zone].
   ///
-  /// These are the [IOOverrides] that will be used in the root Zone, and in
-  /// Zone's that do not set [IOOverrides] and whose ancestors up to the root
-  /// Zone do not set [IOOverrides].
+  /// These are the [IOOverrides] that will be used in the root [Zone], and in
+  /// [Zone]'s that do not set [IOOverrides] and whose ancestors up to the root
+  /// [Zone] also do not set [IOOverrides].
   static set global(IOOverrides? overrides) {
     _global = overrides;
   }
 
   /// Runs [body] in a fresh [Zone] using the provided overrides.
   ///
-  /// See the documentation on the corresponding methods of IOOverrides for
+  /// See the documentation on the corresponding methods of [IOOverrides] for
   /// information about what the optional arguments do.
   static R runZoned<R>(R body(),
       {
@@ -282,7 +282,7 @@
   /// When this override is installed, this functions overrides the behavior of
   /// `ServerSocket.bind(...)`.
   Future<ServerSocket> serverSocketBind(address, int port,
-      {int backlog: 0, bool v6Only: false, bool shared: false}) {
+      {int backlog = 0, bool v6Only = false, bool shared = false}) {
     return ServerSocket._bind(address, port,
         backlog: backlog, v6Only: v6Only, shared: shared);
   }
@@ -499,9 +499,10 @@
   }
 
   // ServerSocket
+
   @override
   Future<ServerSocket> serverSocketBind(address, int port,
-      {int backlog: 0, bool v6Only: false, bool shared: false}) {
+      {int backlog = 0, bool v6Only = false, bool shared = false}) {
     if (_serverSocketBind != null) {
       return _serverSocketBind!(address, port,
           backlog: backlog, v6Only: v6Only, shared: shared);
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index c484461..cedaeba 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.dart
@@ -4,61 +4,60 @@
 
 part of dart.io;
 
-/**
- * Information about the environment in which the current program is running.
- *
- * Platform provides information such as the operating system,
- * the hostname of the computer, the value of environment variables,
- * the path to the running program,
- * and so on.
- *
- * ## Get the URI to the current Dart script
- *
- * Use the [script] getter to get the URI to the currently running
- * Dart script.
- *
- *     import 'dart:io' show Platform;
- *
- *     void main() {
- *       // Get the URI of the script being run.
- *       var uri = Platform.script;
- *       // Convert the URI to a path.
- *       var path = uri.toFilePath();
- *     }
- *
- * ## Get the value of an environment variable
- *
- * The [environment] getter returns a the names and values of environment
- * variables in a [Map] that contains key-value pairs of strings. The Map is
- * unmodifiable. This sample shows how to get the value of the `PATH`
- * environment variable.
- *
- *     import 'dart:io' show Platform;
- *
- *     void main() {
- *       Map<String, String> envVars = Platform.environment;
- *       print(envVars['PATH']);
- *     }
- *
- * ## Determine the OS
- *
- * You can get the name of the operating system as a string with the
- * [operatingSystem] getter. You can also use one of the static boolean
- * getters: [isMacOS], [isLinux], and [isWindows].
- *
- *     import 'dart:io' show Platform, stdout;
- *
- *     void main() {
- *       // Get the operating system as a string.
- *       String os = Platform.operatingSystem;
- *       // Or, use a predicate getter.
- *       if (Platform.isMacOS) {
- *         print('is a Mac');
- *       } else {
- *         print('is not a Mac');
- *       }
- *     }
- */
+/// Information about the environment in which the current program is running.
+///
+/// Platform provides information such as the operating system,
+/// the hostname of the computer, the value of environment variables,
+/// the path to the running program,
+/// and other global properties of the program being run.
+///
+/// ## Get the URI of the current Dart script
+///
+/// Use the [script] getter to get the URI to the currently running
+/// Dart script.
+/// ```dart
+/// import 'dart:io' show Platform;
+///
+/// void main() {
+///   // Get the URI of the script being run.
+///   var uri = Platform.script;
+///   // Convert the URI to a path.
+///   var path = uri.toFilePath();
+/// }
+/// ```
+/// ## Get the value of an environment variable
+///
+/// The [environment] getter returns a the names and values of environment
+/// variables in a [Map] that contains key-value pairs of strings. The Map is
+/// unmodifiable. This sample shows how to get the value of the `PATH`
+/// environment variable.
+/// ```dart
+/// import 'dart:io' show Platform;
+///
+/// void main() {
+///   Map<String, String> envVars = Platform.environment;
+///   print(envVars['PATH']);
+/// }
+/// ```
+/// ## Determine the OS
+///
+/// You can get the name of the operating system as a string with the
+/// [operatingSystem] getter. You can also use one of the static boolean
+/// getters: [isMacOS], [isLinux], and [isWindows].
+/// ```dart
+/// import 'dart:io' show Platform, stdout;
+///
+/// void main() {
+///   // Get the operating system as a string.
+///   String os = Platform.operatingSystem;
+///   // Or, use a predicate getter.
+///   if (Platform.isMacOS) {
+///     print('is a Mac');
+///   } else {
+///     print('is not a Mac');
+///   }
+/// }
+/// ```
 class Platform {
   static final _numberOfProcessors = _Platform.numberOfProcessors;
   static final _pathSeparator = _Platform.pathSeparator;
@@ -67,160 +66,120 @@
   static final _localHostname = _Platform.localHostname;
   static final _version = _Platform.version;
 
-  /**
-   * The number of individual execution units of the machine.
-   */
+  /// The number of individual execution units of the machine.
   static int get numberOfProcessors => _numberOfProcessors;
 
-  /**
-   * The path separator used by the operating system to separate
-   * components in file paths.
-   */
+  /// The path separator used by the operating system to separate
+  /// components in file paths.
   static String get pathSeparator => _pathSeparator;
 
-  /**
-   * Get the name of the current locale.
-   */
+  /// Get the name of the current locale.
   static String get localeName => _Platform.localeName();
 
-  /**
-   * A string representing the operating system or platform.
-   */
+  /// A string representing the operating system or platform.
   static String get operatingSystem => _operatingSystem;
 
-  /**
-   * A string representing the version of the operating system or platform.
-   */
+  /// A string representing the version of the operating system or platform.
   static String get operatingSystemVersion => _operatingSystemVersion;
 
-  /**
-   * The local hostname for the system.
-   */
+  /// The local hostname for the system.
   static String get localHostname => _localHostname;
 
-  /**
-   * Whether the operating system is a version of
-   * [Linux](https://en.wikipedia.org/wiki/Linux).
-   *
-   * This value is `false` if the operating system is a specialized
-   * version of Linux that identifies itself by a different name,
-   * for example Android (see [isAndroid]).
-   */
+  /// Whether the operating system is a version of
+  /// [Linux](https://en.wikipedia.org/wiki/Linux).
+  ///
+  /// This value is `false` if the operating system is a specialized
+  /// version of Linux that identifies itself by a different name,
+  /// for example Android (see [isAndroid]).
   static final bool isLinux = (_operatingSystem == "linux");
 
-  /**
-   * Whether the operating system is a version of
-   * [macOS](https://en.wikipedia.org/wiki/MacOS).
-   */
+  /// Whether the operating system is a version of
+  /// [macOS](https://en.wikipedia.org/wiki/MacOS).
   static final bool isMacOS = (_operatingSystem == "macos");
 
-  /**
-   * Whether the operating system is a version of
-   * [Microsoft Windows](https://en.wikipedia.org/wiki/Microsoft_Windows).
-   */
+  /// Whether the operating system is a version of
+  /// [Microsoft Windows](https://en.wikipedia.org/wiki/Microsoft_Windows).
   static final bool isWindows = (_operatingSystem == "windows");
 
-  /**
-   * Whether the operating system is a version of
-   * [Android](https://en.wikipedia.org/wiki/Android_%28operating_system%29).
-   */
+  /// Whether the operating system is a version of
+  /// [Android](https://en.wikipedia.org/wiki/Android_%28operating_system%29).
   static final bool isAndroid = (_operatingSystem == "android");
 
-  /**
-   * Whether the operating system is a version of
-   * [iOS](https://en.wikipedia.org/wiki/IOS).
-   */
+  /// Whether the operating system is a version of
+  /// [iOS](https://en.wikipedia.org/wiki/IOS).
   static final bool isIOS = (_operatingSystem == "ios");
 
-  /**
-   * Whether the operating system is a version of
-   * [Fuchsia](https://en.wikipedia.org/wiki/Google_Fuchsia).
-   */
+  /// Whether the operating system is a version of
+  /// [Fuchsia](https://en.wikipedia.org/wiki/Google_Fuchsia).
   static final bool isFuchsia = (_operatingSystem == "fuchsia");
 
-  /**
-   * The environment for this process as a map from string key to string value.
-   *
-   * The map is unmodifiable,
-   * and its content is retrieved from the operating system on its first use.
-   *
-   * Environment variables on Windows are case-insensitive,
-   * so on Windows the map is case-insensitive and will convert
-   * all keys to upper case.
-   * On other platforms, keys can be distinguished by case.
-   */
+  /// The environment for this process as a map from string key to string value.
+  ///
+  /// The map is unmodifiable,
+  /// and its content is retrieved from the operating system on its first use.
+  ///
+  /// Environment variables on Windows are case-insensitive,
+  /// so on Windows the map is case-insensitive and will convert
+  /// all keys to upper case.
+  /// On other platforms, keys can be distinguished by case.
   static Map<String, String> get environment => _Platform.environment;
 
-  /**
-   * The path of the executable used to run the script in this isolate.
-   *
-   * The literal path used to identify the script.
-   * This path might be relative or just be a name from which the executable
-   * was found by searching the system path.
-   *
-   * Use [resolvedExecutable] to get an absolute path to the executable.
-   */
+  /// The path of the executable used to run the script in this isolate.
+  ///
+  /// The literal path used to identify the script.
+  /// This path might be relative or just be a name from which the executable
+  /// was found by searching the system path.
+  ///
+  /// Use [resolvedExecutable] to get an absolute path to the executable.
   static String get executable => _Platform.executable;
 
-  /**
-   * The path of the executable used to run the script in this
-   * isolate after it has been resolved by the OS.
-   *
-   * This is the absolute path, with all symlinks resolved, to the
-   * executable used to run the script.
-   */
+  /// The path of the executable used to run the script in this
+  /// isolate after it has been resolved by the OS.
+  ///
+  /// This is the absolute path, with all symlinks resolved, to the
+  /// executable used to run the script.
   static String get resolvedExecutable => _Platform.resolvedExecutable;
 
-  /**
-   * The absolute URI of the script being run in this isolate.
-   *
-   * If the script argument on the command line is relative,
-   * it is resolved to an absolute URI before fetching the script, and
-   * that absolute URI is returned.
-   *
-   * URI resolution only does string manipulation on the script path, and this
-   * may be different from the file system's path resolution behavior. For
-   * example, a symbolic link immediately followed by '..' will not be
-   * looked up.
-   *
-   * If the executable environment does not support [script],
-   * the URI is empty.
-   */
+  /// The absolute URI of the script being run in this isolate.
+  ///
+  /// If the script argument on the command line is relative,
+  /// it is resolved to an absolute URI before fetching the script, and
+  /// that absolute URI is returned.
+  ///
+  /// URI resolution only does string manipulation on the script path, and this
+  /// may be different from the file system's path resolution behavior. For
+  /// example, a symbolic link immediately followed by '..' will not be
+  /// looked up.
+  ///
+  /// If the executable environment does not support [script],
+  /// the URI is empty.
   static Uri get script => _Platform.script;
 
-  /**
-   * The flags passed to the executable used to run the script in this isolate.
-   *
-   * These are the command-line flags to the executable that precedes
-   * the script name.
-   * Provides a new list every time the value is read.
-   */
+  /// The flags passed to the executable used to run the script in this isolate.
+  ///
+  /// These are the command-line flags to the executable that precedes
+  /// the script name.
+  /// Provides a new list every time the value is read.
   static List<String> get executableArguments => _Platform.executableArguments;
 
-  /**
-   * This returns `null`, as `packages/` directories are no longer supported.
-   *
-   */
+  /// This returns `null`, as `packages/` directories are no longer supported.
+  ///
   @Deprecated('packages/ directory resolution is not supported in Dart 2')
   static String? get packageRoot => null; // TODO(mfairhurst): remove this
 
-  /**
-   * The `--packages` flag passed to the executable used to run the script
-   * in this isolate.
-   *
-   * If present, it specifies a file describing how Dart packages are looked up.
-   *
-   * Is `null` if there is no `--packages` flag.
-   */
+  /// The `--packages` flag passed to the executable used to run the script
+  /// in this isolate.
+  ///
+  /// If present, it specifies a file describing how Dart packages are looked up.
+  ///
+  /// Is `null` if there is no `--packages` flag.
   static String? get packageConfig => _Platform.packageConfig;
 
-  /**
-   * The version of the current Dart runtime.
-   *
-   * The value is a [semantic versioning](http://semver.org)
-   * string representing the version of the current Dart runtime,
-   * possibly followed by whitespace and other version and
-   * build details.
-   */
+  /// The version of the current Dart runtime.
+  ///
+  /// The value is a [semantic versioning](http://semver.org)
+  /// string representing the version of the current Dart runtime,
+  /// possibly followed by whitespace and other version and
+  /// build details.
   static String get version => _version;
 }
diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart
index 0251445..48d89ef 100644
--- a/sdk/lib/io/platform_impl.dart
+++ b/sdk/lib/io/platform_impl.dart
@@ -13,21 +13,19 @@
   external static _executable();
   external static _resolvedExecutable();
 
-  /**
-   * Retrieve the entries of the process environment.
-   *
-   * The result is an [Iterable] of strings, where each string represents
-   * an environment entry.
-   *
-   * Environment entries should be strings containing
-   * a non-empty name and a value separated by a '=' character.
-   * The name does not contain a '=' character,
-   * so the name is everything up to the first '=' character.
-   * Values are everything after the first '=' character.
-   * A value may contain further '=' characters, and it may be empty.
-   *
-   * Returns an [OSError] if retrieving the environment fails.
-   */
+  /// Retrieve the entries of the process environment.
+  ///
+  /// The result is an [Iterable] of strings, where each string represents
+  /// an environment entry.
+  ///
+  /// Environment entries should be strings containing
+  /// a non-empty name and a value separated by a '=' character.
+  /// The name does not contain a '=' character,
+  /// so the name is everything up to the first '=' character.
+  /// Values are everything after the first '=' character.
+  /// A value may contain further '=' characters, and it may be empty.
+  ///
+  /// Returns an [OSError] if retrieving the environment fails.
   external static _environment();
   external static List<String> _executableArguments();
   external static String? _packageConfig();
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index d976baf..a1ccce6 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -15,40 +15,38 @@
   external static Stream<ProcessSignal> _watchSignal(ProcessSignal signal);
 }
 
-/**
- * Exit the Dart VM process immediately with the given exit code.
- *
- * This does not wait for any asynchronous operations to terminate nor execute
- * `finally` blocks. Using [exit] is therefore very likely to lose data.
- *
- * While debugging, the VM will not respect the `--pause-isolates-on-exit`
- * flag if [exit] is called as invoking this method causes the Dart VM
- * process to shutdown immediately. To properly break on exit, consider
- * calling [debugger] from `dart:developer` or [Isolate.pause] from
- * `dart:isolate` on [Isolate.current] to pause the isolate before
- * invoking [exit].
- *
- * The handling of exit codes is platform specific.
- *
- * On Linux and OS X an exit code for normal termination will always
- * be in the range [0..255]. If an exit code outside this range is
- * set the actual exit code will be the lower 8 bits masked off and
- * treated as an unsigned value. E.g. using an exit code of -1 will
- * result in an actual exit code of 255 being reported.
- *
- * On Windows the exit code can be set to any 32-bit value. However
- * some of these values are reserved for reporting system errors like
- * crashes.
- *
- * Besides this the Dart executable itself uses an exit code of `254`
- * for reporting compile time errors and an exit code of `255` for
- * reporting runtime error (unhandled exception).
- *
- * Due to these facts it is recommended to only use exit codes in the
- * range [0..127] for communicating the result of running a Dart
- * program to the surrounding environment. This will avoid any
- * cross-platform issues.
- */
+/// Exit the Dart VM process immediately with the given exit code.
+///
+/// This does not wait for any asynchronous operations to terminate nor execute
+/// `finally` blocks. Using [exit] is therefore very likely to lose data.
+///
+/// While debugging, the VM will not respect the `--pause-isolates-on-exit`
+/// flag if [exit] is called as invoking this method causes the Dart VM
+/// process to shutdown immediately. To properly break on exit, consider
+/// calling [debugger] from `dart:developer` or [Isolate.pause] from
+/// `dart:isolate` on [Isolate.current] to pause the isolate before
+/// invoking [exit].
+///
+/// The handling of exit codes is platform specific.
+///
+/// On Linux and OS X an exit code for normal termination will always
+/// be in the range [0..255]. If an exit code outside this range is
+/// set the actual exit code will be the lower 8 bits masked off and
+/// treated as an unsigned value. E.g. using an exit code of -1 will
+/// result in an actual exit code of 255 being reported.
+///
+/// On Windows the exit code can be set to any 32-bit value. However
+/// some of these values are reserved for reporting system errors like
+/// crashes.
+///
+/// Besides this the Dart executable itself uses an exit code of `254`
+/// for reporting compile time errors and an exit code of `255` for
+/// reporting runtime error (unhandled exception).
+///
+/// Due to these facts it is recommended to only use exit codes in the
+/// range \[0..127\] for communicating the result of running a Dart
+/// program to the surrounding environment. This will avoid any
+/// cross-platform issues.
 Never exit(int code) {
   ArgumentError.checkNotNull(code, "code");
   if (!_EmbedderConfig._mayExit) {
@@ -58,41 +56,35 @@
   _ProcessUtils._exit(code);
 }
 
-/**
- * Set the global exit code for the Dart VM.
- *
- * The exit code is global for the Dart VM and the last assignment to
- * exitCode from any isolate determines the exit code of the Dart VM
- * on normal termination.
- *
- * Default value is `0`.
- *
- * See [exit] for more information on how to chose a value for the
- * exit code.
- */
+/// Set the global exit code for the Dart VM.
+///
+/// The exit code is global for the Dart VM and the last assignment to
+/// exitCode from any isolate determines the exit code of the Dart VM
+/// on normal termination.
+///
+/// Default value is `0`.
+///
+/// See [exit] for more information on how to chose a value for the
+/// exit code.
 void set exitCode(int code) {
   ArgumentError.checkNotNull(code, "code");
   _ProcessUtils._setExitCode(code);
 }
 
-/**
- * Get the global exit code for the Dart VM.
- *
- * The exit code is global for the Dart VM and the last assignment to
- * exitCode from any isolate determines the exit code of the Dart VM
- * on normal termination.
- *
- * See [exit] for more information on how to chose a value for the
- * exit code.
- */
+/// Get the global exit code for the Dart VM.
+///
+/// The exit code is global for the Dart VM and the last assignment to
+/// exitCode from any isolate determines the exit code of the Dart VM
+/// on normal termination.
+///
+/// See [exit] for more information on how to chose a value for the
+/// exit code.
 int get exitCode => _ProcessUtils._getExitCode();
 
-/**
- * Sleep for the duration specified in [duration].
- *
- * Use this with care, as no asynchronous operations can be processed
- * in a isolate while it is blocked in a [sleep] call.
- */
+/// Sleep for the duration specified in [duration].
+///
+/// Use this with care, as no asynchronous operations can be processed
+/// in a isolate while it is blocked in a [sleep] call.
 void sleep(Duration duration) {
   int milliseconds = duration.inMilliseconds;
   if (milliseconds < 0) {
@@ -105,41 +97,30 @@
   _ProcessUtils._sleep(milliseconds);
 }
 
-/**
- * Returns the PID of the current process.
- */
+/// Returns the PID of the current process.
 int get pid => _ProcessUtils._pid(null);
 
-/**
- * [ProcessInfo] provides methods for retrieving information about the
- * current process.
- */
+/// Methods for retrieving information about the current process.
 class ProcessInfo {
-  /**
-   * The current resident set size of memory for the process.
-   *
-   * Note that the meaning of this field is platform dependent. For example,
-   * some memory accounted for here may be shared with other processes, or if
-   * the same page is mapped into a process's address space, it may be counted
-   * twice.
-   */
+  /// The current resident set size of memory for the process.
+  ///
+  /// Note that the meaning of this field is platform dependent. For example,
+  /// some memory accounted for here may be shared with other processes, or if
+  /// the same page is mapped into a process's address space, it may be counted
+  /// twice.
   external static int get currentRss;
 
-  /**
-   * The high-watermark in bytes for the resident set size of memory for the
-   * process.
-   *
-   * Note that the meaning of this field is platform dependent. For example,
-   * some memory accounted for here may be shared with other processes, or if
-   * the same page is mapped into a process's address space, it may be counted
-   * twice.
-   */
+  /// The high-watermark in bytes for the resident set size of memory for the
+  /// process.
+  ///
+  /// Note that the meaning of this field is platform dependent. For example,
+  /// some memory accounted for here may be shared with other processes, or if
+  /// the same page is mapped into a process's address space, it may be counted
+  /// twice.
   external static int get maxRss;
 }
 
-/**
- * Modes for running a new process.
- */
+/// Modes for running a new process.
 class ProcessStartMode {
   /// Normal child process.
   static const normal = const ProcessStartMode._internal(0);
@@ -175,362 +156,325 @@
   const ProcessStartMode._internal(this._mode);
 }
 
-/**
- * The means to execute a program.
- *
- * Use the static [start] and [run] methods to start a new process.
- * The run method executes the process non-interactively to completion.
- * In contrast, the start method allows your code to interact with the
- * running process.
- *
- * ## Start a process with the run method
- *
- * The following code sample uses the run method to create a process
- * that runs the UNIX command `ls`, which lists the contents of a directory.
- * The run method completes with a [ProcessResult] object when the process
- * terminates. This provides access to the output and exit code from the
- * process. The run method does not return a Process object; this prevents your
- * code from interacting with the running process.
- *
- *     import 'dart:io';
- *
- *     main() {
- *       // List all files in the current directory in UNIX-like systems.
- *       Process.run('ls', ['-l']).then((ProcessResult results) {
- *         print(results.stdout);
- *       });
- *     }
- *
- * ## Start a process with the start method
- *
- * The following example uses start to create the process.
- * The start method returns a [Future] for a Process object.
- * When the future completes the process is started and
- * your code can interact with the
- * Process: writing to stdin, listening to stdout, and so on.
- *
- * The following sample starts the UNIX `cat` utility, which when given no
- * command-line arguments, echos its input.
- * The program writes to the process's standard input stream
- * and prints data from its standard output stream.
- *
- *     import 'dart:io';
- *     import 'dart:convert';
- *
- *     main() {
- *       Process.start('cat', []).then((Process process) {
- *         process.stdout
- *             .transform(utf8.decoder)
- *             .listen((data) { print(data); });
- *         process.stdin.writeln('Hello, world!');
- *         process.stdin.writeln('Hello, galaxy!');
- *         process.stdin.writeln('Hello, universe!');
- *       });
- *     }
- *
- * ## Standard I/O streams
- *
- * As seen in the previous code sample, you can interact with the Process's
- * standard output stream through the getter [stdout],
- * and you can interact with the Process's standard input stream through
- * the getter [stdin].
- * In addition, Process provides a getter [stderr] for using the Process's
- * standard error stream.
- *
- * A Process's streams are distinct from the top-level streams
- * for the current program.
- *
- * ## Exit codes
- *
- * Call the [exitCode] method to get the exit code of the process.
- * The exit code indicates whether the program terminated successfully
- * (usually indicated with an exit code of 0) or with an error.
- *
- * If the start method is used, the exitCode is available through a future
- * on the Process object (as shown in the example below).
- * If the run method is used, the exitCode is available
- * through a getter on the ProcessResult instance.
- *
- *     import 'dart:io';
- *
- *     main() {
- *       Process.start('ls', ['-l']).then((process) {
- *         // Get the exit code from the new process.
- *         process.exitCode.then((exitCode) {
- *           print('exit code: $exitCode');
- *         });
- *       });
- *     }
- */
+/// The means to execute a program.
+///
+/// Use the static [start] and [run] methods to start a new process.
+/// The run method executes the process non-interactively to completion.
+/// In contrast, the start method allows your code to interact with the
+/// running process.
+///
+/// ## Start a process with the run method
+///
+/// The following code sample uses the run method to create a process
+/// that runs the UNIX command `ls`, which lists the contents of a directory.
+/// The run method completes with a [ProcessResult] object when the process
+/// terminates. This provides access to the output and exit code from the
+/// process. The run method does not return a `Process` object;
+/// this prevents your code from interacting with the running process.
+/// ```dart
+/// import 'dart:io';
+///
+/// main() async {
+///   // List all files in the current directory in UNIX-like systems.
+///   var result = await Process.run('ls', ['-l']);
+///   print(results.stdout);
+/// }
+/// ```
+/// ## Start a process with the start method
+///
+/// The following example uses start to create the process.
+/// The start method returns a [Future] for a `Process` object.
+/// When the future completes the process is started and
+/// your code can interact with the process:
+/// writing to stdin, listening to stdout, and so on.
+///
+/// The following sample starts the UNIX `cat` utility, which when given no
+/// command-line arguments, echos its input.
+/// The program writes to the process's standard input stream
+/// and prints data from its standard output stream.
+/// ```dart
+/// import 'dart:io';
+/// import 'dart:convert';
+///
+/// main() async {
+///   var process = await Process.start('cat', []);
+///   process.stdout
+///       .transform(utf8.decoder)
+///       .forEach(print);
+///   process.stdin.writeln('Hello, world!');
+///   process.stdin.writeln('Hello, galaxy!');
+///   process.stdin.writeln('Hello, universe!');
+/// }
+/// ```
+/// ## Standard I/O streams
+///
+/// As seen in the previous code sample, you can interact with the `Process`'s
+/// standard output stream through the getter [stdout],
+/// and you can interact with the `Process`'s standard input stream through
+/// the getter [stdin].
+/// In addition, `Process` provides a getter [stderr] for using the `Process`'s
+/// standard error stream.
+///
+/// A `Process`'s streams are distinct from the top-level streams
+/// for the current program.
+///
+/// ## Exit codes
+///
+/// Call the [exitCode] method to get the exit code of the process.
+/// The exit code indicates whether the program terminated successfully
+/// (usually indicated with an exit code of 0) or with an error.
+///
+/// If the start method is used, the [exitCode] is available through a future
+/// on the `Process` object (as shown in the example below).
+/// If the run method is used, the [exitCode] is available
+/// through a getter on the [ProcessResult] instance.
+/// ```dart
+/// import 'dart:io';
+///
+/// main() async {
+///   var process = Process.start('ls', ['-l']);
+///   var exitCode = await process.exitCode;
+///   print('exit code: $exitCode');
+/// }
+/// ```
 abstract class Process {
-  /**
-   * Returns a [:Future:] which completes with the exit code of the process
-   * when the process completes.
-   *
-   * The handling of exit codes is platform specific.
-   *
-   * On Linux and OS X a normal exit code will be a positive value in
-   * the range [0..255]. If the process was terminated due to a signal
-   * the exit code will be a negative value in the range [-255..-1],
-   * where the absolute value of the exit code is the signal
-   * number. For example, if a process crashes due to a segmentation
-   * violation the exit code will be -11, as the signal SIGSEGV has the
-   * number 11.
-   *
-   * On Windows a process can report any 32-bit value as an exit
-   * code. When returning the exit code this exit code is turned into
-   * a signed value. Some special values are used to report
-   * termination due to some system event. E.g. if a process crashes
-   * due to an access violation the 32-bit exit code is `0xc0000005`,
-   * which will be returned as the negative number `-1073741819`. To
-   * get the original 32-bit value use `(0x100000000 + exitCode) &
-   * 0xffffffff`.
-   *
-   * There is no guarantee that [stdout] and [stderr] have finished reporting
-   * the buffered output of the process when the returned future completes.
-   * To be sure that all output is captured,
-   * wait for the done event on the streams.
-   */
+  /// A `Future` which completes with the exit code of the process
+  /// when the process completes.
+  ///
+  /// The handling of exit codes is platform specific.
+  ///
+  /// On Linux and OS X a normal exit code will be a positive value in
+  /// the range [0..255]. If the process was terminated due to a signal
+  /// the exit code will be a negative value in the range [-255..-1],
+  /// where the absolute value of the exit code is the signal
+  /// number. For example, if a process crashes due to a segmentation
+  /// violation the exit code will be -11, as the signal SIGSEGV has the
+  /// number 11.
+  ///
+  /// On Windows a process can report any 32-bit value as an exit
+  /// code. When returning the exit code this exit code is turned into
+  /// a signed value. Some special values are used to report
+  /// termination due to some system event. E.g. if a process crashes
+  /// due to an access violation the 32-bit exit code is `0xc0000005`,
+  /// which will be returned as the negative number `-1073741819`. To
+  /// get the original 32-bit value use `(0x100000000 + exitCode) &
+  /// 0xffffffff`.
+  ///
+  /// There is no guarantee that [stdout] and [stderr] have finished reporting
+  /// the buffered output of the process when the returned future completes.
+  /// To be sure that all output is captured,
+  /// wait for the done event on the streams.
   Future<int> get exitCode;
 
-  /**
-   * Starts a process running the [executable] with the specified
-   * [arguments]. Returns a [:Future<Process>:] that completes with a
-   * Process instance when the process has been successfully
-   * started. That [Process] object can be used to interact with the
-   * process. If the process cannot be started the returned [Future]
-   * completes with an exception.
-   *
-   * Use [workingDirectory] to set the working directory for the process. Note
-   * that the change of directory occurs before executing the process on some
-   * platforms, which may have impact when using relative paths for the
-   * executable and the arguments.
-   *
-   * Use [environment] to set the environment variables for the process. If not
-   * set the environment of the parent process is inherited. Currently, only
-   * US-ASCII environment variables are supported and errors are likely to occur
-   * if an environment variable with code-points outside the US-ASCII range is
-   * passed in.
-   *
-   * If [includeParentEnvironment] is `true`, the process's environment will
-   * include the parent process's environment, with [environment] taking
-   * precedence. Default is `true`.
-   *
-   * If [runInShell] is `true`, the process will be spawned through a system
-   * shell. On Linux and OS X, [:/bin/sh:] is used, while
-   * [:%WINDIR%\system32\cmd.exe:] is used on Windows.
-   *
-   * Users must read all data coming on the [stdout] and [stderr]
-   * streams of processes started with [:Process.start:]. If the user
-   * does not read all data on the streams the underlying system
-   * resources will not be released since there is still pending data.
-   *
-   * The following code uses `Process.start` to grep for `main` in the
-   * file `test.dart` on Linux.
-   *
-   *     Process.start('grep', ['-i', 'main', 'test.dart']).then((process) {
-   *       stdout.addStream(process.stdout);
-   *       stderr.addStream(process.stderr);
-   *     });
-   *
-   * If [mode] is [ProcessStartMode.normal] (the default) a child
-   * process will be started with `stdin`, `stdout` and `stderr`
-   * connected.
-   *
-   * If `mode` is [ProcessStartMode.detached] a detached process will
-   * be created. A detached process has no connection to its parent,
-   * and can keep running on its own when the parent dies. The only
-   * information available from a detached process is its `pid`. There
-   * is no connection to its `stdin`, `stdout` or `stderr`, nor will
-   * the process' exit code become available when it terminates.
-   *
-   * If `mode` is [ProcessStartMode.detachedWithStdio] a detached
-   * process will be created where the `stdin`, `stdout` and `stderr`
-   * are connected. The creator can communicate with the child through
-   * these. The detached process will keep running even if these
-   * communication channels are closed. The process' exit code will
-   * not become available when it terminated.
-   *
-   * The default value for `mode` is `ProcessStartMode.normal`.
-   */
+  /// Starts a process running the [executable] with the specified
+  /// [arguments].
+  ///
+  /// Returns a `Future<Process>` that completes with a
+  /// [Process] instance when the process has been successfully
+  /// started. That [Process] object can be used to interact with the
+  /// process. If the process cannot be started the returned [Future]
+  /// completes with an exception.
+  ///
+  /// Use [workingDirectory] to set the working directory for the process. Note
+  /// that the change of directory occurs before executing the process on some
+  /// platforms, which may have impact when using relative paths for the
+  /// executable and the arguments.
+  ///
+  /// Use [environment] to set the environment variables for the process. If not
+  /// set the environment of the parent process is inherited. Currently, only
+  /// US-ASCII environment variables are supported and errors are likely to occur
+  /// if an environment variable with code-points outside the US-ASCII range is
+  /// passed in.
+  ///
+  /// If [includeParentEnvironment] is `true`, the process's environment will
+  /// include the parent process's environment, with [environment] taking
+  /// precedence. Default is `true`.
+  ///
+  /// If [runInShell] is `true`, the process will be spawned through a system
+  /// shell. On Linux and OS X, `/bin/sh` is used, while
+  /// `%WINDIR%\system32\cmd.exe` is used on Windows.
+  ///
+  /// Users must read all data coming on the [stdout] and [stderr]
+  /// streams of processes started with `Process.start`. If the user
+  /// does not read all data on the streams the underlying system
+  /// resources will not be released since there is still pending data.
+  ///
+  /// The following code uses `Process.start` to grep for `main` in the
+  /// file `test.dart` on Linux.
+  /// ```dart
+  /// var process = await Process.start('grep', ['-i', 'main', 'test.dart']);
+  /// stdout.addStream(process.stdout);
+  /// stderr.addStream(process.stderr);
+  /// ```
+  /// If [mode] is [ProcessStartMode.normal] (the default) a child
+  /// process will be started with `stdin`, `stdout` and `stderr`
+  /// connected.
+  ///
+  /// If `mode` is [ProcessStartMode.detached] a detached process will
+  /// be created. A detached process has no connection to its parent,
+  /// and can keep running on its own when the parent dies. The only
+  /// information available from a detached process is its `pid`. There
+  /// is no connection to its `stdin`, `stdout` or `stderr`, nor will
+  /// the process' exit code become available when it terminates.
+  ///
+  /// If `mode` is [ProcessStartMode.detachedWithStdio] a detached
+  /// process will be created where the `stdin`, `stdout` and `stderr`
+  /// are connected. The creator can communicate with the child through
+  /// these. The detached process will keep running even if these
+  /// communication channels are closed. The process' exit code will
+  /// not become available when it terminated.
+  ///
+  /// The default value for `mode` is `ProcessStartMode.normal`.
   external static Future<Process> start(
       String executable, List<String> arguments,
       {String? workingDirectory,
       Map<String, String>? environment,
-      bool includeParentEnvironment: true,
-      bool runInShell: false,
-      ProcessStartMode mode: ProcessStartMode.normal});
+      bool includeParentEnvironment = true,
+      bool runInShell = false,
+      ProcessStartMode mode = ProcessStartMode.normal});
 
-  /**
-   * Starts a process and runs it non-interactively to completion. The
-   * process run is [executable] with the specified [arguments].
-   *
-   * Use [workingDirectory] to set the working directory for the process. Note
-   * that the change of directory occurs before executing the process on some
-   * platforms, which may have impact when using relative paths for the
-   * executable and the arguments.
-   *
-   * Use [environment] to set the environment variables for the process. If not
-   * set the environment of the parent process is inherited. Currently, only
-   * US-ASCII environment variables are supported and errors are likely to occur
-   * if an environment variable with code-points outside the US-ASCII range is
-   * passed in.
-   *
-   * If [includeParentEnvironment] is `true`, the process's environment will
-   * include the parent process's environment, with [environment] taking
-   * precedence. Default is `true`.
-   *
-   * If [runInShell] is true, the process will be spawned through a system
-   * shell. On Linux and OS X, `/bin/sh` is used, while
-   * `%WINDIR%\system32\cmd.exe` is used on Windows.
-   *
-   * The encoding used for decoding `stdout` and `stderr` into text is
-   * controlled through [stdoutEncoding] and [stderrEncoding]. The
-   * default encoding is [systemEncoding]. If `null` is used no
-   * decoding will happen and the [ProcessResult] will hold binary
-   * data.
-   *
-   * Returns a `Future<ProcessResult>` that completes with the
-   * result of running the process, i.e., exit code, standard out and
-   * standard in.
-   *
-   * The following code uses `Process.run` to grep for `main` in the
-   * file `test.dart` on Linux.
-   *
-   *     Process.run('grep', ['-i', 'main', 'test.dart']).then((result) {
-   *       stdout.write(result.stdout);
-   *       stderr.write(result.stderr);
-   *     });
-   */
+  /// Starts a process and runs it non-interactively to completion. The
+  /// process run is [executable] with the specified [arguments].
+  ///
+  /// Use [workingDirectory] to set the working directory for the process. Note
+  /// that the change of directory occurs before executing the process on some
+  /// platforms, which may have impact when using relative paths for the
+  /// executable and the arguments.
+  ///
+  /// Use [environment] to set the environment variables for the process. If not
+  /// set the environment of the parent process is inherited. Currently, only
+  /// US-ASCII environment variables are supported and errors are likely to occur
+  /// if an environment variable with code-points outside the US-ASCII range is
+  /// passed in.
+  ///
+  /// If [includeParentEnvironment] is `true`, the process's environment will
+  /// include the parent process's environment, with [environment] taking
+  /// precedence. Default is `true`.
+  ///
+  /// If [runInShell] is true, the process will be spawned through a system
+  /// shell. On Linux and OS X, `/bin/sh` is used, while
+  /// `%WINDIR%\system32\cmd.exe` is used on Windows.
+  ///
+  /// The encoding used for decoding `stdout` and `stderr` into text is
+  /// controlled through [stdoutEncoding] and [stderrEncoding]. The
+  /// default encoding is [systemEncoding]. If `null` is used no
+  /// decoding will happen and the [ProcessResult] will hold binary
+  /// data.
+  ///
+  /// Returns a `Future<ProcessResult>` that completes with the
+  /// result of running the process, i.e., exit code, standard out and
+  /// standard in.
+  ///
+  /// The following code uses `Process.run` to grep for `main` in the
+  /// file `test.dart` on Linux.
+  /// ```dart
+  /// var result = await Process.run('grep', ['-i', 'main', 'test.dart']);
+  /// stdout.write(result.stdout);
+  /// stderr.write(result.stderr);
+  /// ```
   external static Future<ProcessResult> run(
       String executable, List<String> arguments,
       {String? workingDirectory,
       Map<String, String>? environment,
-      bool includeParentEnvironment: true,
-      bool runInShell: false,
-      Encoding? stdoutEncoding: systemEncoding,
-      Encoding? stderrEncoding: systemEncoding});
+      bool includeParentEnvironment = true,
+      bool runInShell = false,
+      Encoding? stdoutEncoding = systemEncoding,
+      Encoding? stderrEncoding = systemEncoding});
 
-  /**
-   * Starts a process and runs it to completion. This is a synchronous
-   * call and will block until the child process terminates.
-   *
-   * The arguments are the same as for `Process.run`.
-   *
-   * Returns a `ProcessResult` with the result of running the process,
-   * i.e., exit code, standard out and standard in.
-   */
+  /// Starts a process and runs it to completion. This is a synchronous
+  /// call and will block until the child process terminates.
+  ///
+  /// The arguments are the same as for [Process.run].
+  ///
+  /// Returns a [ProcessResult] with the result of running the process,
+  /// i.e., exit code, standard out and standard in.
   external static ProcessResult runSync(
       String executable, List<String> arguments,
       {String? workingDirectory,
       Map<String, String>? environment,
-      bool includeParentEnvironment: true,
-      bool runInShell: false,
-      Encoding? stdoutEncoding: systemEncoding,
-      Encoding? stderrEncoding: systemEncoding});
+      bool includeParentEnvironment = true,
+      bool runInShell = false,
+      Encoding? stdoutEncoding = systemEncoding,
+      Encoding? stderrEncoding = systemEncoding});
 
-  /**
-   * Kills the process with id [pid].
-   *
-   * Where possible, sends the [signal] to the process with id
-   * `pid`. This includes Linux and OS X. The default signal is
-   * [ProcessSignal.sigterm] which will normally terminate the
-   * process.
-   *
-   * On platforms without signal support, including Windows, the call
-   * just terminates the process with id `pid` in a platform specific
-   * way, and the `signal` parameter is ignored.
-   *
-   * Returns `true` if the signal is successfully delivered to the
-   * process. Otherwise the signal could not be sent, usually meaning
-   * that the process is already dead.
-   */
+  /// Kills the process with id [pid].
+  ///
+  /// Where possible, sends the [signal] to the process with id
+  /// [pid]. This includes Linux and OS X. The default signal is
+  /// [ProcessSignal.sigterm] which will normally terminate the
+  /// process.
+  ///
+  /// On platforms without signal support, including Windows, the call
+  /// just terminates the process with id [pid] in a platform specific
+  /// way, and the [signal] parameter is ignored.
+  ///
+  /// Returns `true` if the signal is successfully delivered to the
+  /// process. Otherwise the signal could not be sent, usually meaning
+  /// that the process is already dead.
   external static bool killPid(int pid,
       [ProcessSignal signal = ProcessSignal.sigterm]);
 
-  /**
-   * Returns the standard output stream of the process as a [:Stream:].
-   */
+  /// The standard output stream of the process as a `Stream`.
   Stream<List<int>> get stdout;
 
-  /**
-   * Returns the standard error stream of the process as a [:Stream:].
-   */
+  /// The standard error stream of the process as a `Stream`.
   Stream<List<int>> get stderr;
 
-  /**
-   * Returns the standard input stream of the process as an [IOSink].
-   */
+  /// The standard input stream of the process as an [IOSink].
   IOSink get stdin;
 
-  /**
-   * Returns the process id of the process.
-   */
+  /// The process id of the process.
   int get pid;
 
-  /**
-   * Kills the process.
-   *
-   * Where possible, sends the [signal] to the process. This includes
-   * Linux and OS X. The default signal is [ProcessSignal.sigterm]
-   * which will normally terminate the process.
-   *
-   * On platforms without signal support, including Windows, the call
-   * just terminates the process in a platform specific way, and the
-   * `signal` parameter is ignored.
-   *
-   * Returns `true` if the signal is successfully delivered to the
-   * process. Otherwise the signal could not be sent, usually meaning
-   * that the process is already dead.
-   */
+  /// Kills the process.
+  ///
+  /// Where possible, sends the [signal] to the process. This includes
+  /// Linux and OS X. The default signal is [ProcessSignal.sigterm]
+  /// which will normally terminate the process.
+  ///
+  /// On platforms without signal support, including Windows, the call
+  /// just terminates the process in a platform specific way, and the
+  /// [signal] parameter is ignored.
+  ///
+  /// Returns `true` if the signal is successfully delivered to the
+  /// process. Otherwise the signal could not be sent, usually meaning
+  /// that the process is already dead.
   bool kill([ProcessSignal signal = ProcessSignal.sigterm]);
 }
 
-/**
- * [ProcessResult] represents the result of running a non-interactive
- * process started with [Process.run] or [Process.runSync].
- */
+/// The result of running a non-interactive
+/// process started with [Process.run] or [Process.runSync].
 class ProcessResult {
-  /**
-   * Exit code for the process.
-   *
-   * See [Process.exitCode] for more information in the exit code
-   * value.
-   */
+  /// Exit code for the process.
+  ///
+  /// See [Process.exitCode] for more information in the exit code
+  /// value.
   final int exitCode;
 
-  /**
-   * Standard output from the process. The value used for the
-   * `stdoutEncoding` argument to `Process.run` determines the type. If
-   * `null` was used this value is of type `List<int>` otherwise it is
-   * of type `String`.
-   */
+  /// Standard output from the process. The value used for the
+  /// `stdoutEncoding` argument to `Process.run` determines the type. If
+  /// `null` was used, this value is of type `List<int>` otherwise it is
+  /// of type `String`.
   final stdout;
 
-  /**
-   * Standard error from the process. The value used for the
-   * `stderrEncoding` argument to `Process.run` determines the type. If
-   * `null` was used this value is of type `List<int>`
-   * otherwise it is of type `String`.
-   */
+  /// Standard error from the process. The value used for the
+  /// `stderrEncoding` argument to `Process.run` determines the type. If
+  /// `null` was used, this value is of type `List<int>`
+  /// otherwise it is of type `String`.
   final stderr;
 
-  /**
-   * Process id of the process.
-   */
+  /// Process id of the process.
   final int pid;
 
   ProcessResult(this.pid, this.exitCode, this.stdout, this.stderr);
 }
 
-/**
- * On Posix systems, [ProcessSignal] is used to send a specific signal
- * to a child process, see [:Process.kill:].
- *
- * Some [ProcessSignal]s can also be watched, as a way to intercept the default
- * signal handler and implement another. See [ProcessSignal.watch] for more
- * information.
- */
+/// On Posix systems, [ProcessSignal] is used to send a specific signal
+/// to a child process, see `Process.kill`.
+///
+/// Some [ProcessSignal]s can also be watched, as a way to intercept the default
+/// signal handler and implement another. See [ProcessSignal.watch] for more
+/// information.
 class ProcessSignal {
   static const ProcessSignal sighup = const ProcessSignal._(1, "SIGHUP");
   static const ProcessSignal sigint = const ProcessSignal._(2, "SIGINT");
@@ -628,23 +572,21 @@
 
   String toString() => _name;
 
-  /**
-   * Watch for process signals.
-   *
-   * The following [ProcessSignal]s can be listened to:
-   *
-   *   * [ProcessSignal.sighup].
-   *   * [ProcessSignal.sigint]. Signal sent by e.g. CTRL-C.
-   *   * [ProcessSignal.sigterm]. Not available on Windows.
-   *   * [ProcessSignal.sigusr1]. Not available on Windows.
-   *   * [ProcessSignal.sigusr2]. Not available on Windows.
-   *   * [ProcessSignal.sigwinch]. Not available on Windows.
-   *
-   * Other signals are disallowed, as they may be used by the VM.
-   *
-   * A signal can be watched multiple times, from multiple isolates, where all
-   * callbacks are invoked when signaled, in no specific order.
-   */
+  /// Watch for process signals.
+  ///
+  /// The following [ProcessSignal]s can be listened to:
+  ///
+  ///   * [ProcessSignal.sighup].
+  ///   * [ProcessSignal.sigint]. Signal sent by e.g. CTRL-C.
+  ///   * [ProcessSignal.sigterm]. Not available on Windows.
+  ///   * [ProcessSignal.sigusr1]. Not available on Windows.
+  ///   * [ProcessSignal.sigusr2]. Not available on Windows.
+  ///   * [ProcessSignal.sigwinch]. Not available on Windows.
+  ///
+  /// Other signals are disallowed, as they may be used by the VM.
+  ///
+  /// A signal can be watched multiple times, from multiple isolates, where all
+  /// callbacks are invoked when signaled, in no specific order.
   Stream<ProcessSignal> watch() => _ProcessUtils._watchSignal(this);
 }
 
@@ -664,24 +606,20 @@
 }
 
 class ProcessException implements IOException {
-  /**
-   * Contains the executable provided for the process.
-   */
+  /// The executable provided for the process.
   final String executable;
 
-  /**
-   * Contains the arguments provided for the process.
-   */
+  /// The arguments provided for the process.
   final List<String> arguments;
 
-  /**
-   * Contains the system message for the process exception if any.
-   */
+  /// The system message for the process exception, if any.
+  ///
+  /// The empty string if no message was available.
   final String message;
 
-  /**
-   * Contains the OS error code for the process exception if any.
-   */
+  /// The OS error code for the process exception, if any.
+  ///
+  /// The value is zero if no OS error code was available.
   final int errorCode;
 
   const ProcessException(this.executable, this.arguments,
diff --git a/sdk/lib/io/secure_server_socket.dart b/sdk/lib/io/secure_server_socket.dart
index dbdcc28..bfe34af 100644
--- a/sdk/lib/io/secure_server_socket.dart
+++ b/sdk/lib/io/secure_server_socket.dart
@@ -4,76 +4,72 @@
 
 part of dart.io;
 
-/**
- * The [SecureServerSocket] is a server socket, providing a stream of high-level
- * [Socket]s.
- *
- * See [SecureSocket] for more info.
- */
+/// A server socket, providing a stream of high-level [Socket]s.
+///
+/// See [SecureSocket] for more info.
 class SecureServerSocket extends Stream<SecureSocket> {
   final RawSecureServerSocket _socket;
 
   SecureServerSocket._(this._socket);
 
-  /**
-   * Returns a future for a [SecureServerSocket]. When the future
-   * completes the server socket is bound to the given [address] and
-   * [port] and has started listening on it.
-   *
-   * The [address] can either be a [String] or an
-   * [InternetAddress]. If [address] is a [String], [bind] will
-   * perform a [InternetAddress.lookup] and use the first value in the
-   * list. To listen on the loopback adapter, which will allow only
-   * incoming connections from the local host, use the value
-   * [InternetAddress.loopbackIPv4] or
-   * [InternetAddress.loopbackIPv6]. To allow for incoming
-   * connection from the network use either one of the values
-   * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
-   * bind to all interfaces or the IP address of a specific interface.
-   *
-   * If [port] has the value [:0:] an ephemeral port will be chosen by
-   * the system. The actual port used can be retrieved using the
-   * [port] getter.
-   *
-   * The optional argument [backlog] can be used to specify the listen
-   * backlog for the underlying OS listen setup. If [backlog] has the
-   * value of [:0:] (the default) a reasonable value will be chosen by
-   * the system.
-   *
-   * Incoming client connections are promoted to secure connections, using
-   * the server certificate and key set in [context].
-   *
-   * [address] must be given as a numeric address, not a host name.
-   *
-   * To request or require that clients authenticate by providing an SSL (TLS)
-   * client certificate, set the optional parameter [requestClientCertificate]
-   * or [requireClientCertificate] to true.  Requiring a certificate implies
-   * requesting a certificate, so setting both is redundant.
-   * To check whether a client certificate was received, check
-   * SecureSocket.peerCertificate after connecting.  If no certificate
-   * was received, the result will be null.
-   *
-   * [supportedProtocols] is an optional list of protocols (in decreasing
-   * order of preference) to use during the ALPN protocol negogiation with
-   * clients.  Example values are "http/1.1" or "h2".  The selected protocol
-   * can be obtained via [SecureSocket.selectedProtocol].
-   *
-   * The optional argument [shared] specifies whether additional
-   * SecureServerSocket objects can bind to the same combination of `address`,
-   * `port` and `v6Only`.  If `shared` is `true` and more `SecureServerSocket`s
-   * from this isolate or other isolates are bound to the port, then the
-   * incoming connections will be distributed among all the bound
-   * `SecureServerSocket`s. Connections can be distributed over multiple
-   * isolates this way.
-   */
+  /// Listens on a given address and port.
+  ///
+  /// When the returned future completes, the server socket is bound
+  /// to the given [address] and [port] and has started listening on it.
+  ///
+  /// The [address] can either be a [String] or an
+  /// [InternetAddress]. If [address] is a [String], [bind] will
+  /// perform a [InternetAddress.lookup] and use the first value in the
+  /// list. To listen on the loopback adapter, which will allow only
+  /// incoming connections from the local host, use the value
+  /// [InternetAddress.loopbackIPv4] or
+  /// [InternetAddress.loopbackIPv6]. To allow for incoming
+  /// connection from the network use either one of the values
+  /// [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+  /// bind to all interfaces or the IP address of a specific interface.
+  ///
+  /// If [port] has the value `0`, an ephemeral port will be chosen by
+  /// the system. The actual port used can be retrieved using the
+  /// [port] getter.
+  ///
+  /// The optional argument [backlog] can be used to specify the listen
+  /// backlog for the underlying OS listen setup. If [backlog] has the
+  /// value of `0` (the default) a reasonable value will be chosen by
+  /// the system.
+  ///
+  /// Incoming client connections are promoted to secure connections, using
+  /// the server certificate and key set in [context].
+  ///
+  /// The [address] must be given as a numeric address, not a host name.
+  ///
+  /// To request or require that clients authenticate by providing an SSL (TLS)
+  /// client certificate, set the optional parameter [requestClientCertificate]
+  /// or [requireClientCertificate] to true.  Requiring a certificate implies
+  /// requesting a certificate, so setting both is redundant.
+  /// To check whether a client certificate was received, check
+  /// [SecureSocket.peerCertificate] after connecting.  If no certificate
+  /// was received, the result will be null.
+  ///
+  /// [supportedProtocols] is an optional list of protocols (in decreasing
+  /// order of preference) to use during the ALPN protocol negogiation with
+  /// clients.  Example values are "http/1.1" or "h2".  The selected protocol
+  /// can be obtained via [SecureSocket.selectedProtocol].
+  ///
+  /// The optional argument [shared] specifies whether additional
+  /// [SecureServerSocket] objects can bind to the same combination of [address],
+  /// [port] and [v6Only].  If [shared] is `true` and more [SecureServerSocket]s
+  /// from this isolate or other isolates are bound to the same port, then the
+  /// incoming connections will be distributed among all the bound
+  /// `SecureServerSocket`s. Connections can be distributed over multiple
+  /// isolates this way.
   static Future<SecureServerSocket> bind(
       address, int port, SecurityContext? context,
-      {int backlog: 0,
-      bool v6Only: false,
-      bool requestClientCertificate: false,
-      bool requireClientCertificate: false,
+      {int backlog = 0,
+      bool v6Only = false,
+      bool requestClientCertificate = false,
+      bool requireClientCertificate = false,
       List<String>? supportedProtocols,
-      bool shared: false}) {
+      bool shared = false}) {
     return RawSecureServerSocket.bind(address, port, context,
             backlog: backlog,
             v6Only: v6Only,
@@ -93,20 +89,16 @@
         cancelOnError: cancelOnError);
   }
 
-  /**
-   * Returns the port used by this socket.
-   */
+  /// The port used by this socket.
   int get port => _socket.port;
 
-  /**
-   * Returns the address used by this socket.
-   */
+  /// The address used by this socket.
   InternetAddress get address => _socket.address;
 
-  /**
-   * Closes the socket. The returned future completes when the socket
-   * is fully closed and is no longer bound.
-   */
+  /// Closes this socket.
+  ///
+  /// The returned future completes when the socket
+  /// is fully closed and is no longer bound.
   Future<SecureServerSocket> close() => _socket.close().then((_) => this);
 
   void set _owner(owner) {
@@ -114,12 +106,9 @@
   }
 }
 
-/**
- * The RawSecureServerSocket is a server socket, providing a stream of low-level
- * [RawSecureSocket]s.
- *
- * See [RawSecureSocket] for more info.
- */
+/// A server socket providing a stream of low-level [RawSecureSocket]s.
+///
+/// See [RawSecureSocket] for more info.
 class RawSecureServerSocket extends Stream<RawSecureSocket> {
   final RawServerSocket _socket;
   late StreamController<RawSecureSocket> _controller;
@@ -144,64 +133,63 @@
         onCancel: _onSubscriptionStateChange);
   }
 
-  /**
-   * Returns a future for a [RawSecureServerSocket]. When the future
-   * completes the server socket is bound to the given [address] and
-   * [port] and has started listening on it.
-   *
-   * The [address] can either be a [String] or an
-   * [InternetAddress]. If [address] is a [String], [bind] will
-   * perform a [InternetAddress.lookup] and use the first value in the
-   * list. To listen on the loopback adapter, which will allow only
-   * incoming connections from the local host, use the value
-   * [InternetAddress.loopbackIPv4] or
-   * [InternetAddress.loopbackIPv6]. To allow for incoming
-   * connection from the network use either one of the values
-   * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
-   * bind to all interfaces or the IP address of a specific interface.
-   *
-   * If [port] has the value [:0:] an ephemeral port will be chosen by
-   * the system. The actual port used can be retrieved using the
-   * [port] getter.
-   *
-   * The optional argument [backlog] can be used to specify the listen
-   * backlog for the underlying OS listen setup. If [backlog] has the
-   * value of [:0:] (the default) a reasonable value will be chosen by
-   * the system.
-   *
-   * Incoming client connections are promoted to secure connections,
-   * using the server certificate and key set in [context].
-   *
-   * [address] must be given as a numeric address, not a host name.
-   *
-   * To request or require that clients authenticate by providing an SSL (TLS)
-   * client certificate, set the optional parameters requestClientCertificate or
-   * requireClientCertificate to true.  Require implies request, so one doesn't
-   * need to specify both.  To check whether a client certificate was received,
-   * check SecureSocket.peerCertificate after connecting.  If no certificate
-   * was received, the result will be null.
-   *
-   * [supportedProtocols] is an optional list of protocols (in decreasing
-   * order of preference) to use during the ALPN protocol negotiation with
-   * clients.  Example values are "http/1.1" or "h2".  The selected protocol
-   * can be obtained via [RawSecureSocket.selectedProtocol].
-   *
-   * The optional argument [shared] specifies whether additional
-   * RawSecureServerSocket objects can bind to the same combination of
-   * `address`, `port` and `v6Only`.  If `shared` is `true` and more
-   * `RawSecureServerSocket`s from this isolate or other isolates are bound to
-   * the port, then the incoming connections will be distributed among all the
-   * bound `RawSecureServerSocket`s. Connections can be distributed over
-   * multiple isolates this way.
-   */
+  /// Listens on a provided address and port.
+  ///
+  /// When the returned future completes, the server socket is bound
+  /// to the given [address] and [port] and has started listening on it.
+  ///
+  /// The [address] can either be a [String] or an
+  /// [InternetAddress]. If [address] is a [String], [bind] will
+  /// perform a [InternetAddress.lookup] and use the first value in the
+  /// list. To listen on the loopback adapter, which will allow only
+  /// incoming connections from the local host, use the value
+  /// [InternetAddress.loopbackIPv4] or
+  /// [InternetAddress.loopbackIPv6]. To allow for incoming
+  /// connection from the network use either one of the values
+  /// [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+  /// bind to all interfaces or the IP address of a specific interface.
+  ///
+  /// If [port] has the value `0` an ephemeral port will be chosen by
+  /// the system. The actual port used can be retrieved using the
+  /// [port] getter.
+  ///
+  /// The optional argument [backlog] can be used to specify the listen
+  /// backlog for the underlying OS listen setup. If [backlog] has the
+  /// value of `0` (the default) a reasonable value will be chosen by
+  /// the system.
+  ///
+  /// Incoming client connections are promoted to secure connections,
+  /// using the server certificate and key set in [context].
+  ///
+  /// [address] must be given as a numeric address, not a host name.
+  ///
+  /// To request or require that clients authenticate by providing an SSL (TLS)
+  /// client certificate, set the optional parameters requestClientCertificate or
+  /// requireClientCertificate to true.  Require implies request, so one doesn't
+  /// need to specify both.  To check whether a client certificate was received,
+  /// check SecureSocket.peerCertificate after connecting.  If no certificate
+  /// was received, the result will be null.
+  ///
+  /// [supportedProtocols] is an optional list of protocols (in decreasing
+  /// order of preference) to use during the ALPN protocol negotiation with
+  /// clients.  Example values are "http/1.1" or "h2".  The selected protocol
+  /// can be obtained via [RawSecureSocket.selectedProtocol].
+  ///
+  /// The optional argument [shared] specifies whether additional
+  /// [RawSecureServerSocket] objects can bind to the same combination of
+  /// [address], [port] and [v6Only].  If [shared] is `true` and more
+  /// [RawSecureServerSocket]s from this isolate or other isolates are bound to
+  /// the port, then the incoming connections will be distributed among all the
+  /// bound [RawSecureServerSocket]s. Connections can be distributed over
+  /// multiple isolates this way.
   static Future<RawSecureServerSocket> bind(
       address, int port, SecurityContext? context,
-      {int backlog: 0,
-      bool v6Only: false,
-      bool requestClientCertificate: false,
-      bool requireClientCertificate: false,
+      {int backlog = 0,
+      bool v6Only = false,
+      bool requestClientCertificate = false,
+      bool requireClientCertificate = false,
       List<String>? supportedProtocols,
-      bool shared: false}) {
+      bool shared = false}) {
     return RawServerSocket.bind(address, port,
             backlog: backlog, v6Only: v6Only, shared: shared)
         .then((serverSocket) => new RawSecureServerSocket._(
@@ -218,20 +206,16 @@
         onError: onError, onDone: onDone, cancelOnError: cancelOnError);
   }
 
-  /**
-   * Returns the port used by this socket.
-   */
+  /// The port used by this socket.
   int get port => _socket.port;
 
-  /**
-   * Returns the address used by this socket.
-   */
+  /// The address used by this socket.
   InternetAddress get address => _socket.address;
 
-  /**
-   * Closes the socket. The returned future completes when the socket
-   * is fully closed and is no longer bound.
-   */
+  /// Closes this socket.
+  ///
+  /// The returned future completes when the socket
+  /// is fully closed and is no longer bound.
   Future<RawSecureServerSocket> close() {
     _closed = true;
     return _socket.close().then((_) => this);
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 185b116..32222b5 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -4,43 +4,39 @@
 
 part of dart.io;
 
-/**
- * A high-level class for communicating securely over a TCP socket, using
- * TLS and SSL. The [SecureSocket] exposes both a [Stream] and an
- * [IOSink] interface, making it ideal for using together with
- * other [Stream]s.
- */
+/// A TCP socket using TLS and SSL.
+///
+/// A secure socket may be used as either a [Stream] or an [IOSink].
 abstract class SecureSocket implements Socket {
   external factory SecureSocket._(RawSecureSocket rawSocket);
 
-  /**
-   * Constructs a new secure client socket and connects it to the given
-   * [host] on port [port]. The returned Future will complete with a
-   * [SecureSocket] that is connected and ready for subscription.
-   *
-   * The certificate provided by the server is checked
-   * using the trusted certificates set in the SecurityContext object.
-   * The default SecurityContext object contains a built-in set of trusted
-   * root certificates for well-known certificate authorities.
-   *
-   * [onBadCertificate] is an optional handler for unverifiable certificates.
-   * The handler receives the [X509Certificate], and can inspect it and
-   * decide (or let the user decide) whether to accept
-   * the connection or not.  The handler should return true
-   * to continue the [SecureSocket] connection.
-   *
-   * [supportedProtocols] is an optional list of protocols (in decreasing
-   * order of preference) to use during the ALPN protocol negotiation with the
-   * server.  Example values are "http/1.1" or "h2".  The selected protocol
-   * can be obtained via [SecureSocket.selectedProtocol].
-   *
-   * The argument [timeout] is used to specify the maximum allowed time to wait
-   * for a connection to be established. If [timeout] is longer than the system
-   * level timeout duration, a timeout may occur sooner than specified in
-   * [timeout]. On timeout, a [SocketException] is thrown and all ongoing
-   * connection attempts to [host] are cancelled.
-
-   */
+  /// Constructs a new secure client socket and connects it to the given
+  /// [host] on port [port].
+  ///
+  /// The returned Future will complete with a
+  /// [SecureSocket] that is connected and ready for subscription.
+  ///
+  /// The certificate provided by the server is checked
+  /// using the trusted certificates set in the SecurityContext object.
+  /// The default SecurityContext object contains a built-in set of trusted
+  /// root certificates for well-known certificate authorities.
+  ///
+  /// [onBadCertificate] is an optional handler for unverifiable certificates.
+  /// The handler receives the [X509Certificate], and can inspect it and
+  /// decide (or let the user decide) whether to accept
+  /// the connection or not.  The handler should return true
+  /// to continue the [SecureSocket] connection.
+  ///
+  /// [supportedProtocols] is an optional list of protocols (in decreasing
+  /// order of preference) to use during the ALPN protocol negotiation with the
+  /// server.  Example values are "http/1.1" or "h2".  The selected protocol
+  /// can be obtained via [SecureSocket.selectedProtocol].
+  ///
+  /// The argument [timeout] is used to specify the maximum allowed time to wait
+  /// for a connection to be established. If [timeout] is longer than the system
+  /// level timeout duration, a timeout may occur sooner than specified in
+  /// [timeout]. On timeout, a [SocketException] is thrown and all ongoing
+  /// connection attempts to [host] are cancelled.
   static Future<SecureSocket> connect(host, int port,
       {SecurityContext? context,
       bool onBadCertificate(X509Certificate certificate)?,
@@ -72,39 +68,38 @@
     });
   }
 
-  /**
-   * Takes an already connected [socket] and starts client side TLS
-   * handshake to make the communication secure. When the returned
-   * future completes the [SecureSocket] has completed the TLS
-   * handshake. Using this function requires that the other end of the
-   * connection is prepared for TLS handshake.
-   *
-   * If the [socket] already has a subscription, this subscription
-   * will no longer receive and events. In most cases calling
-   * `pause` on this subscription before starting TLS handshake is
-   * the right thing to do.
-   *
-   * The given [socket] is closed and may not be used anymore.
-   *
-   * If the [host] argument is passed it will be used as the host name
-   * for the TLS handshake. If [host] is not passed the host name from
-   * the [socket] will be used. The [host] can be either a [String] or
-   * an [InternetAddress].
-   *
-   * [supportedProtocols] is an optional list of protocols (in decreasing
-   * order of preference) to use during the ALPN protocol negotiation with the
-   * server.  Example values are "http/1.1" or "h2".  The selected protocol
-   * can be obtained via [SecureSocket.selectedProtocol].
-   *
-   * Calling this function will _not_ cause a DNS host lookup. If the
-   * [host] passed is a [String] the [InternetAddress] for the
-   * resulting [SecureSocket] will have the passed in [host] as its
-   * host value and the internet address of the already connected
-   * socket as its address value.
-   *
-   * See [connect] for more information on the arguments.
-   *
-   */
+  /// Initiates TLS on an existing connection.
+  ///
+  /// Takes an already connected [socket] and starts client side TLS
+  /// handshake to make the communication secure. When the returned
+  /// future completes the [SecureSocket] has completed the TLS
+  /// handshake. Using this function requires that the other end of the
+  /// connection is prepared for TLS handshake.
+  ///
+  /// If the [socket] already has a subscription, this subscription
+  /// will no longer receive and events. In most cases calling
+  /// [StreamSubscription.pause] on this subscription before
+  /// starting TLS handshake is the right thing to do.
+  ///
+  /// The given [socket] is closed and may not be used anymore.
+  ///
+  /// If the [host] argument is passed it will be used as the host name
+  /// for the TLS handshake. If [host] is not passed the host name from
+  /// the [socket] will be used. The [host] can be either a [String] or
+  /// an [InternetAddress].
+  ///
+  /// [supportedProtocols] is an optional list of protocols (in decreasing
+  /// order of preference) to use during the ALPN protocol negotiation with the
+  /// server.  Example values are "http/1.1" or "h2".  The selected protocol
+  /// can be obtained via [SecureSocket.selectedProtocol].
+  ///
+  /// Calling this function will _not_ cause a DNS host lookup. If the
+  /// [host] passed is a [String], the [InternetAddress] for the
+  /// resulting [SecureSocket] will have the passed in [host] as its
+  /// host value and the internet address of the already connected
+  /// socket as its address value.
+  ///
+  /// See [connect] for more information on the arguments.
   static Future<SecureSocket> secure(Socket socket,
       {host,
       SecurityContext? context,
@@ -121,32 +116,31 @@
     }).then<SecureSocket>((raw) => new SecureSocket._(raw));
   }
 
-  /**
-   * Takes an already connected [socket] and starts server side TLS
-   * handshake to make the communication secure. When the returned
-   * future completes the [SecureSocket] has completed the TLS
-   * handshake. Using this function requires that the other end of the
-   * connection is going to start the TLS handshake.
-   *
-   * If the [socket] already has a subscription, this subscription
-   * will no longer receive and events. In most cases calling
-   * [:pause:] on this subscription before starting TLS handshake is
-   * the right thing to do.
-   *
-   * If some of the data of the TLS handshake has already been read
-   * from the socket this data can be passed in the [bufferedData]
-   * parameter. This data will be processed before any other data
-   * available on the socket.
-   *
-   * See [SecureServerSocket.bind] for more information on the
-   * arguments.
-   *
-   */
+  /// Initiates TLS on an existing server connection.
+  ///
+  /// Takes an already connected [socket] and starts server side TLS
+  /// handshake to make the communication secure. When the returned
+  /// future completes the [SecureSocket] has completed the TLS
+  /// handshake. Using this function requires that the other end of the
+  /// connection is going to start the TLS handshake.
+  ///
+  /// If the [socket] already has a subscription, this subscription
+  /// will no longer receive and events. In most cases calling
+  /// [StreamSubscription.pause] on this subscription
+  /// before starting TLS handshake is the right thing to do.
+  ///
+  /// If some of the data of the TLS handshake has already been read
+  /// from the socket this data can be passed in the [bufferedData]
+  /// parameter. This data will be processed before any other data
+  /// available on the socket.
+  ///
+  /// See [SecureServerSocket.bind] for more information on the
+  /// arguments.
   static Future<SecureSocket> secureServer(
       Socket socket, SecurityContext? context,
       {List<int>? bufferedData,
-      bool requestClientCertificate: false,
-      bool requireClientCertificate: false,
+      bool requestClientCertificate = false,
+      bool requireClientCertificate = false,
       List<String>? supportedProtocols}) {
     return ((socket as dynamic /*_Socket*/)._detachRaw() as Future)
         .then<RawSecureSocket>((detachedRaw) {
@@ -159,71 +153,66 @@
     }).then<SecureSocket>((raw) => new SecureSocket._(raw));
   }
 
-  /**
-   * Get the peer certificate for a connected SecureSocket.  If this
-   * SecureSocket is the server end of a secure socket connection,
-   * [peerCertificate] will return the client certificate, or null, if no
-   * client certificate was received.  If it is the client end,
-   * [peerCertificate] will return the server's certificate.
-   */
+  /// The peer certificate for a connected SecureSocket.
+  ///
+  /// If this [SecureSocket] is the server end of a secure socket connection,
+  /// [peerCertificate] will return the client certificate, or `null` if no
+  /// client certificate was received.  If this socket is the client end,
+  /// [peerCertificate] will return the server's certificate.
   X509Certificate? get peerCertificate;
 
-  /**
-   * The protocol which was selected during ALPN protocol negotiation.
-   *
-   * Returns null if one of the peers does not have support for ALPN, did not
-   * specify a list of supported ALPN protocols or there was no common
-   * protocol between client and server.
-   */
+  /// The protocol which was selected during ALPN protocol negotiation.
+  ///
+  /// Returns `null` if one of the peers does not have support for ALPN, did not
+  /// specify a list of supported ALPN protocols or there was no common
+  /// protocol between client and server.
   String? get selectedProtocol;
 
-  /**
-   * Renegotiate an existing secure connection, renewing the session keys
-   * and possibly changing the connection properties.
-   *
-   * This repeats the SSL or TLS handshake, with options that allow clearing
-   * the session cache and requesting a client certificate.
-   */
+  /// Renegotiates an existing secure connection.
+  ///
+  /// Renews the session keys and possibly changes the connection properties.
+  ///
+  /// This repeats the SSL or TLS handshake, with options that allow clearing
+  /// the session cache and requesting a client certificate.
   void renegotiate(
-      {bool useSessionCache: true,
-      bool requestClientCertificate: false,
-      bool requireClientCertificate: false});
+      {bool useSessionCache = true,
+      bool requestClientCertificate = false,
+      bool requireClientCertificate = false});
 }
 
-/**
- * RawSecureSocket provides a secure (SSL or TLS) network connection.
- * Client connections to a server are provided by calling
- * RawSecureSocket.connect.  A secure server, created with
- * [RawSecureServerSocket], also returns RawSecureSocket objects representing
- * the server end of a secure connection.
- * The certificate provided by the server is checked
- * using the trusted certificates set in the SecurityContext object.
- * The default [SecurityContext] object contains a built-in set of trusted
- * root certificates for well-known certificate authorities.
- */
+/// `RawSecureSocket` provides a secure (SSL or TLS) network connection.
+///
+/// Client connections to a server are provided by calling
+/// RawSecureSocket.connect.  A secure server, created with
+/// [RawSecureServerSocket], also returns `RawSecureSocket` objects representing
+/// the server end of a secure connection.
+/// The certificate provided by the server is checked
+/// using the trusted certificates set in the [SecurityContext] object.
+/// The default [SecurityContext] object contains a built-in set of trusted
+/// root certificates for well-known certificate authorities.
 abstract class RawSecureSocket implements RawSocket {
-  /**
-   * Constructs a new secure client socket and connect it to the given
-   * host on the given port. The returned [Future] is completed with the
-   * RawSecureSocket when it is connected and ready for subscription.
-   *
-   * The certificate provided by the server is checked using the trusted
-   * certificates set in the SecurityContext object If a certificate and key are
-   * set on the client, using [SecurityContext.useCertificateChain] and
-   * [SecurityContext.usePrivateKey], and the server asks for a client
-   * certificate, then that client certificate is sent to the server.
-   *
-   * [onBadCertificate] is an optional handler for unverifiable certificates.
-   * The handler receives the [X509Certificate], and can inspect it and
-   * decide (or let the user decide) whether to accept
-   * the connection or not.  The handler should return true
-   * to continue the [RawSecureSocket] connection.
-   *
-   * [supportedProtocols] is an optional list of protocols (in decreasing
-   * order of preference) to use during the ALPN protocol negotiation with the
-   * server.  Example values are "http/1.1" or "h2".  The selected protocol
-   * can be obtained via [RawSecureSocket.selectedProtocol].
-   */
+  /// Constructs a new secure client socket and connect it to the given
+  /// host on the given port.
+  ///
+  /// The returned [Future] is completed with the
+  /// [RawSecureSocket] when it is connected and ready for subscription.
+  ///
+  /// The certificate provided by the server is checked using the trusted
+  /// certificates set in the SecurityContext object If a certificate and key are
+  /// set on the client, using [SecurityContext.useCertificateChain] and
+  /// [SecurityContext.usePrivateKey], and the server asks for a client
+  /// certificate, then that client certificate is sent to the server.
+  ///
+  /// [onBadCertificate] is an optional handler for unverifiable certificates.
+  /// The handler receives the [X509Certificate], and can inspect it and
+  /// decide (or let the user decide) whether to accept
+  /// the connection or not.  The handler should return true
+  /// to continue the [RawSecureSocket] connection.
+  ///
+  /// [supportedProtocols] is an optional list of protocols (in decreasing
+  /// order of preference) to use during the ALPN protocol negotiation with the
+  /// server.  Example values are "http/1.1" or "h2".  The selected protocol
+  /// can be obtained via [RawSecureSocket.selectedProtocol].
   static Future<RawSecureSocket> connect(host, int port,
       {SecurityContext? context,
       bool onBadCertificate(X509Certificate certificate)?,
@@ -257,39 +246,38 @@
     });
   }
 
-  /**
-   * Takes an already connected [socket] and starts client side TLS
-   * handshake to make the communication secure. When the returned
-   * future completes the [RawSecureSocket] has completed the TLS
-   * handshake. Using this function requires that the other end of the
-   * connection is prepared for TLS handshake.
-   *
-   * If the [socket] already has a subscription, pass the existing
-   * subscription in the [subscription] parameter. The [secure]
-   * operation will take over the subscription by replacing the
-   * handlers with it own secure processing. The caller must not touch
-   * this subscription anymore. Passing a paused subscription is an
-   * error.
-   *
-   * If the [host] argument is passed it will be used as the host name
-   * for the TLS handshake. If [host] is not passed the host name from
-   * the [socket] will be used. The [host] can be either a [String] or
-   * an [InternetAddress].
-   *
-   * [supportedProtocols] is an optional list of protocols (in decreasing
-   * order of preference) to use during the ALPN protocol negotiation with the
-   * server.  Example values are "http/1.1" or "h2".  The selected protocol
-   * can be obtained via [SecureSocket.selectedProtocol].
-   *
-   * Calling this function will _not_ cause a DNS host lookup. If the
-   * [host] passed is a [String] the [InternetAddress] for the
-   * resulting [SecureSocket] will have this passed in [host] as its
-   * host value and the internet address of the already connected
-   * socket as its address value.
-   *
-   * See [connect] for more information on the arguments.
-   *
-   */
+  /// Initiates TLS on an existing connection.
+  ///
+  /// Takes an already connected [socket] and starts client side TLS
+  /// handshake to make the communication secure. When the returned
+  /// future completes the [RawSecureSocket] has completed the TLS
+  /// handshake. Using this function requires that the other end of the
+  /// connection is prepared for TLS handshake.
+  ///
+  /// If the [socket] already has a subscription, pass the existing
+  /// subscription in the [subscription] parameter. The [secure]
+  /// operation will take over the subscription by replacing the
+  /// handlers with it own secure processing. The caller must not touch
+  /// this subscription anymore. Passing a paused subscription is an
+  /// error.
+  ///
+  /// If the [host] argument is passed it will be used as the host name
+  /// for the TLS handshake. If [host] is not passed the host name from
+  /// the [socket] will be used. The [host] can be either a [String] or
+  /// an [InternetAddress].
+  ///
+  /// [supportedProtocols] is an optional list of protocols (in decreasing
+  /// order of preference) to use during the ALPN protocol negotiation with the
+  /// server.  Example values are "http/1.1" or "h2".  The selected protocol
+  /// can be obtained via [SecureSocket.selectedProtocol].
+  ///
+  /// Calling this function will _not_ cause a DNS host lookup. If the
+  /// [host] passed is a [String] the [InternetAddress] for the
+  /// resulting [SecureSocket] will have this passed in [host] as its
+  /// host value and the internet address of the already connected
+  /// socket as its address value.
+  ///
+  /// See [connect] for more information on the arguments.
   static Future<RawSecureSocket> secure(RawSocket socket,
       {StreamSubscription<RawSocketEvent>? subscription,
       host,
@@ -306,35 +294,34 @@
         supportedProtocols: supportedProtocols);
   }
 
-  /**
-   * Takes an already connected [socket] and starts server side TLS
-   * handshake to make the communication secure. When the returned
-   * future completes the [RawSecureSocket] has completed the TLS
-   * handshake. Using this function requires that the other end of the
-   * connection is going to start the TLS handshake.
-   *
-   * If the [socket] already has a subscription, pass the existing
-   * subscription in the [subscription] parameter. The [secureServer]
-   * operation will take over the subscription by replacing the
-   * handlers with it own secure processing. The caller must not touch
-   * this subscription anymore. Passing a paused subscription is an
-   * error.
-   *
-   * If some of the data of the TLS handshake has already been read
-   * from the socket this data can be passed in the [bufferedData]
-   * parameter. This data will be processed before any other data
-   * available on the socket.
-   *
-   * See [RawSecureServerSocket.bind] for more information on the
-   * arguments.
-   *
-   */
+  /// Initiates TLS on an existing server connection.
+  ///
+  /// Takes an already connected [socket] and starts server side TLS
+  /// handshake to make the communication secure. When the returned
+  /// future completes the [RawSecureSocket] has completed the TLS
+  /// handshake. Using this function requires that the other end of the
+  /// connection is going to start the TLS handshake.
+  ///
+  /// If the [socket] already has a subscription, pass the existing
+  /// subscription in the [subscription] parameter. The [secureServer]
+  /// operation will take over the subscription by replacing the
+  /// handlers with it own secure processing. The caller must not touch
+  /// this subscription anymore. Passing a paused subscription is an
+  /// error.
+  ///
+  /// If some of the data of the TLS handshake has already been read
+  /// from the socket this data can be passed in the [bufferedData]
+  /// parameter. This data will be processed before any other data
+  /// available on the socket.
+  ///
+  /// See [RawSecureServerSocket.bind] for more information on the
+  /// arguments.
   static Future<RawSecureSocket> secureServer(
       RawSocket socket, SecurityContext? context,
       {StreamSubscription<RawSocketEvent>? subscription,
       List<int>? bufferedData,
-      bool requestClientCertificate: false,
-      bool requireClientCertificate: false,
+      bool requestClientCertificate = false,
+      bool requireClientCertificate = false,
       List<String>? supportedProtocols}) {
     socket.readEventsEnabled = false;
     socket.writeEventsEnabled = false;
@@ -348,41 +335,33 @@
         supportedProtocols: supportedProtocols);
   }
 
-  /**
-   * Renegotiate an existing secure connection, renewing the session keys
-   * and possibly changing the connection properties.
-   *
-   * This repeats the SSL or TLS handshake, with options that allow clearing
-   * the session cache and requesting a client certificate.
-   */
+  /// Renegotiate an existing secure connection, renewing the session keys
+  /// and possibly changing the connection properties.
+  ///
+  /// This repeats the SSL or TLS handshake, with options that allow clearing
+  /// the session cache and requesting a client certificate.
   void renegotiate(
-      {bool useSessionCache: true,
-      bool requestClientCertificate: false,
-      bool requireClientCertificate: false});
+      {bool useSessionCache = true,
+      bool requestClientCertificate = false,
+      bool requireClientCertificate = false});
 
-  /**
-   * Get the peer certificate for a connected RawSecureSocket.  If this
-   * RawSecureSocket is the server end of a secure socket connection,
-   * [peerCertificate] will return the client certificate, or null, if no
-   * client certificate was received.  If it is the client end,
-   * [peerCertificate] will return the server's certificate.
-   */
+  /// Get the peer certificate for a connected RawSecureSocket.  If this
+  /// RawSecureSocket is the server end of a secure socket connection,
+  /// [peerCertificate] will return the client certificate, or null, if no
+  /// client certificate was received.  If it is the client end,
+  /// [peerCertificate] will return the server's certificate.
   X509Certificate? get peerCertificate;
 
-  /**
-   * The protocol which was selected during protocol negotiation.
-   *
-   * Returns null if one of the peers does not have support for ALPN, did not
-   * specify a list of supported ALPN protocols or there was no common
-   * protocol between client and server.
-   */
+  /// The protocol which was selected during protocol negotiation.
+  ///
+  /// Returns null if one of the peers does not have support for ALPN, did not
+  /// specify a list of supported ALPN protocols or there was no common
+  /// protocol between client and server.
   String? get selectedProtocol;
 }
 
-/**
- * X509Certificate represents an SSL certificate, with accessors to
- * get the fields of the certificate.
- */
+/// X509Certificate represents an SSL certificate, with accessors to
+/// get the fields of the certificate.
 @pragma("vm:entry-point")
 abstract class X509Certificate {
   @pragma("vm:entry-point")
@@ -476,8 +455,8 @@
       {SecurityContext? context,
       StreamSubscription<RawSocketEvent>? subscription,
       List<int>? bufferedData,
-      bool requestClientCertificate: false,
-      bool requireClientCertificate: false,
+      bool requestClientCertificate = false,
+      bool requireClientCertificate = false,
       bool onBadCertificate(X509Certificate certificate)?,
       List<String>? supportedProtocols}) {
     _verifyFields(host, requestedPort, requestClientCertificate,
@@ -828,9 +807,9 @@
   }
 
   void renegotiate(
-      {bool useSessionCache: true,
-      bool requestClientCertificate: false,
-      bool requireClientCertificate: false}) {
+      {bool useSessionCache = true,
+      bool requestClientCertificate = false,
+      bool requireClientCertificate = false}) {
     if (_status != connectedStatus) {
       throw new HandshakeException(
           "Called renegotiate on a non-connected socket");
@@ -1108,11 +1087,9 @@
   }
 }
 
-/**
- * A circular buffer backed by an external byte array.  Accessed from
- * both C++ and Dart code in an unsynchronized way, with one reading
- * and one writing.  All updates to start and end are done by Dart code.
- */
+/// A circular buffer backed by an external byte array.  Accessed from
+/// both C++ and Dart code in an unsynchronized way, with one reading
+/// and one writing.  All updates to start and end are done by Dart code.
 class _ExternalBuffer {
   // This will be an ExternalByteArray, backed by C allocated data.
   @pragma("vm:entry-point", "set")
@@ -1263,9 +1240,8 @@
   List<_ExternalBuffer>? get buffers;
 }
 
-/** A secure networking exception caused by a failure in the
- *  TLS/SSL protocol.
- */
+/// A secure networking exception caused by a failure in the
+/// TLS/SSL protocol.
 class TlsException implements IOException {
   final String type;
   final String message;
@@ -1292,10 +1268,8 @@
   }
 }
 
-/**
- * An exception that happens in the handshake phase of establishing
- * a secure network connection.
- */
+/// An exception that happens in the handshake phase of establishing
+/// a secure network connection.
 @pragma("vm:entry-point")
 class HandshakeException extends TlsException {
   @pragma("vm:entry-point")
@@ -1303,11 +1277,9 @@
       : super._("HandshakeException", message, osError);
 }
 
-/**
- * An exception that happens in the handshake phase of establishing
- * a secure network connection, when looking up or verifying a
- * certificate.
- */
+/// An exception that happens in the handshake phase of establishing
+/// a secure network connection, when looking up or verifying a
+/// certificate.
 class CertificateException extends TlsException {
   @pragma("vm:entry-point")
   const CertificateException([String message = "", OSError? osError])
diff --git a/sdk/lib/io/security_context.dart b/sdk/lib/io/security_context.dart
index e4fd5c6..082da28 100644
--- a/sdk/lib/io/security_context.dart
+++ b/sdk/lib/io/security_context.dart
@@ -4,198 +4,176 @@
 
 part of dart.io;
 
-/**
- * The object containing the certificates to trust when making
- * a secure client connection, and the certificate chain and
- * private key to serve from a secure server.
- *
- * The [SecureSocket]  and [SecureServerSocket] classes take a SecurityContext
- * as an argument to their connect and bind methods.
- *
- * Certificates and keys can be added to a SecurityContext from either PEM
- * or PKCS12 containers.
- *
- * iOS note: Some methods to add, remove, and inspect certificates are not yet
- * implemented. However, the platform's built-in trusted certificates can
- * be used, by way of [SecurityContext.defaultContext].
- */
+/// The object containing the certificates to trust when making
+/// a secure client connection, and the certificate chain and
+/// private key to serve from a secure server.
+///
+/// The [SecureSocket]  and [SecureServerSocket] classes take a SecurityContext
+/// as an argument to their connect and bind methods.
+///
+/// Certificates and keys can be added to a SecurityContext from either PEM
+/// or PKCS12 containers.
+///
+/// iOS note: Some methods to add, remove, and inspect certificates are not yet
+/// implemented. However, the platform's built-in trusted certificates can
+/// be used, by way of [SecurityContext.defaultContext].
 abstract class SecurityContext {
-  /**
-   * Creates a new [SecurityContext].
-   *
-   * By default, the created [SecurityContext] contains no keys or certificates.
-   * These can be added by calling the methods of this class.
-   *
-   * If `withTrustedRoots` is passed as `true`, the [SecurityContext] will be
-   * seeded by the trusted root certificates provided as explained below. To
-   * obtain a [SecurityContext] containing trusted root certificates,
-   * [SecurityContext.defaultContext] is usually sufficient, and should
-   * be used instead. However, if the [SecurityContext] containing the trusted
-   * root certificates must be modified per-connection, then `withTrustedRoots`
-   * should be used.
-   */
-  external factory SecurityContext({bool withTrustedRoots: false});
+  /// Creates a new [SecurityContext].
+  ///
+  /// By default, the created [SecurityContext] contains no keys or certificates.
+  /// These can be added by calling the methods of this class.
+  ///
+  /// If [withTrustedRoots] is passed as `true`, the [SecurityContext] will be
+  /// seeded by the trusted root certificates provided as explained below. To
+  /// obtain a [SecurityContext] containing trusted root certificates,
+  /// [SecurityContext.defaultContext] is usually sufficient, and should
+  /// be used instead. However, if the [SecurityContext] containing the trusted
+  /// root certificates must be modified per-connection, then [withTrustedRoots]
+  /// should be used.
+  external factory SecurityContext({bool withTrustedRoots = false});
 
-  /**
-   * Secure networking classes with an optional `context` parameter
-   * use the [defaultContext] object if the parameter is omitted.
-   * This object can also be accessed, and modified, directly.
-   * Each isolate has a different [defaultContext] object.
-   * The [defaultContext] object uses a list of well-known trusted
-   * certificate authorities as its trusted roots. On Linux and Windows, this
-   * list is taken from Mozilla, who maintains it as part of Firefox. On,
-   * MacOS, iOS, and Android, this list comes from the trusted certificates
-   * stores built in to the platforms.
-   */
+  /// The default security context used by most operation requiring one.
+  ///
+  /// Secure networking classes with an optional `context` parameter
+  /// use the [defaultContext] object if the parameter is omitted.
+  /// This object can also be accessed, and modified, directly.
+  /// Each isolate has a different [defaultContext] object.
+  /// The [defaultContext] object uses a list of well-known trusted
+  /// certificate authorities as its trusted roots. On Linux and Windows, this
+  /// list is taken from Mozilla, who maintains it as part of Firefox. On,
+  /// MacOS, iOS, and Android, this list comes from the trusted certificates
+  /// stores built in to the platforms.
   external static SecurityContext get defaultContext;
 
-  /**
-   * Sets the private key for a server certificate or client certificate.
-   *
-   * A secure connection using this SecurityContext will use this key with
-   * the server or client certificate to sign and decrypt messages.
-   * [file] is the path to a PEM or PKCS12 file containing an encrypted
-   * private key, encrypted with [password]. Assuming it is well-formatted, all
-   * other contents of [file] are ignored. An unencrypted file can be used,
-   * but this is not usual.
-   *
-   * NB: This function calls [File.readAsBytesSync], and will block on file IO.
-   * Prefer using [usePrivateKeyBytes].
-   *
-   * iOS note: Only PKCS12 data is supported. It should contain both the private
-   * key and the certificate chain. On iOS one call to [usePrivateKey] with this
-   * data is used instead of two calls to [useCertificateChain] and
-   * [usePrivateKey].
-   */
+  /// Sets the private key for a server certificate or client certificate.
+  ///
+  /// A secure connection using this SecurityContext will use this key with
+  /// the server or client certificate to sign and decrypt messages.
+  /// [file] is the path to a PEM or PKCS12 file containing an encrypted
+  /// private key, encrypted with [password]. Assuming it is well-formatted, all
+  /// other contents of [file] are ignored. An unencrypted file can be used,
+  /// but this is not usual.
+  ///
+  /// NB: This function calls [File.readAsBytesSync], and will block on file IO.
+  /// Prefer using [usePrivateKeyBytes].
+  ///
+  /// iOS note: Only PKCS12 data is supported. It should contain both the private
+  /// key and the certificate chain. On iOS one call to [usePrivateKey] with this
+  /// data is used instead of two calls to [useCertificateChain] and
+  /// [usePrivateKey].
   void usePrivateKey(String file, {String? password});
 
-  /**
-   * Sets the private key for a server certificate or client certificate.
-   *
-   * Like [usePrivateKey], but takes the contents of the file as a list
-   * of bytes.
-   */
+  /// Sets the private key for a server certificate or client certificate.
+  ///
+  /// Like [usePrivateKey], but takes the contents of the file as a list
+  /// of bytes.
   void usePrivateKeyBytes(List<int> keyBytes, {String? password});
 
-  /**
-   * Sets the set of trusted X509 certificates used by [SecureSocket]
-   * client connections, when connecting to a secure server.
-   *
-   * [file] is the path to a PEM or PKCS12 file containing X509 certificates,
-   * usually root certificates from certificate authorities. For PKCS12 files,
-   * [password] is the password for the file. For PEM files, [password] is
-   * ignored. Assuming it is well-formatted, all other contents of [file] are
-   * ignored.
-   *
-   * NB: This function calls [File.readAsBytesSync], and will block on file IO.
-   * Prefer using [setTrustedCertificatesBytes].
-   *
-   * iOS note: On iOS, this call takes only the bytes for a single DER
-   * encoded X509 certificate. It may be called multiple times to add
-   * multiple trusted certificates to the context. A DER encoded certificate
-   * can be obtained from a PEM encoded certificate by using the openssl tool:
-   *
-   *   $ openssl x509 -outform der -in cert.pem -out cert.der
-   */
+  /// Sets the set of trusted X509 certificates used by [SecureSocket]
+  /// client connections, when connecting to a secure server.
+  ///
+  /// [file] is the path to a PEM or PKCS12 file containing X509 certificates,
+  /// usually root certificates from certificate authorities. For PKCS12 files,
+  /// [password] is the password for the file. For PEM files, [password] is
+  /// ignored. Assuming it is well-formatted, all other contents of [file] are
+  /// ignored.
+  ///
+  /// NB: This function calls [File.readAsBytesSync], and will block on file IO.
+  /// Prefer using [setTrustedCertificatesBytes].
+  ///
+  /// iOS note: On iOS, this call takes only the bytes for a single DER
+  /// encoded X509 certificate. It may be called multiple times to add
+  /// multiple trusted certificates to the context. A DER encoded certificate
+  /// can be obtained from a PEM encoded certificate by using the openssl tool:
+  /// ```
+  /// $ openssl x509 -outform der -in cert.pem -out cert.der
+  /// ```
   void setTrustedCertificates(String file, {String? password});
 
-  /**
-   * Sets the set of trusted X509 certificates used by [SecureSocket]
-   * client connections, when connecting to a secure server.
-   *
-   * Like [setTrustedCertificates] but takes the contents of the file.
-   */
+  /// Sets the set of trusted X509 certificates used by [SecureSocket]
+  /// client connections, when connecting to a secure server.
+  ///
+  /// Like [setTrustedCertificates] but takes the contents of the file.
   void setTrustedCertificatesBytes(List<int> certBytes, {String? password});
 
-  /**
-   * Sets the chain of X509 certificates served by [SecureServerSocket]
-   * when making secure connections, including the server certificate.
-   *
-   * [file] is a PEM or PKCS12 file containing X509 certificates, starting with
-   * the root authority and intermediate authorities forming the signed
-   * chain to the server certificate, and ending with the server certificate.
-   * The private key for the server certificate is set by [usePrivateKey]. For
-   * PKCS12 files, [password] is the password for the file. For PEM files,
-   * [password] is ignored. Assuming it is well-formatted, all
-   * other contents of [file] are ignored.
-   *
-   * NB: This function calls [File.readAsBytesSync], and will block on file IO.
-   * Prefer using [useCertificateChainBytes].
-   *
-   * iOS note: As noted above, [usePrivateKey] does the job of both
-   * that call and this one. On iOS, this call is a no-op.
-   */
+  /// Sets the chain of X509 certificates served by [SecureServerSocket]
+  /// when making secure connections, including the server certificate.
+  ///
+  /// [file] is a PEM or PKCS12 file containing X509 certificates, starting with
+  /// the root authority and intermediate authorities forming the signed
+  /// chain to the server certificate, and ending with the server certificate.
+  /// The private key for the server certificate is set by [usePrivateKey]. For
+  /// PKCS12 files, [password] is the password for the file. For PEM files,
+  /// [password] is ignored. Assuming it is well-formatted, all
+  /// other contents of [file] are ignored.
+  ///
+  /// NB: This function calls [File.readAsBytesSync], and will block on file IO.
+  /// Prefer using [useCertificateChainBytes].
+  ///
+  /// iOS note: As noted above, [usePrivateKey] does the job of both
+  /// that call and this one. On iOS, this call is a no-op.
   void useCertificateChain(String file, {String? password});
 
-  /**
-   * Sets the chain of X509 certificates served by [SecureServerSocket]
-   * when making secure connections, including the server certificate.
-   *
-   * Like [useCertificateChain] but takes the contents of the file.
-   */
+  /// Sets the chain of X509 certificates served by [SecureServerSocket]
+  /// when making secure connections, including the server certificate.
+  ///
+  /// Like [useCertificateChain] but takes the contents of the file.
   void useCertificateChainBytes(List<int> chainBytes, {String? password});
 
-  /**
-   * Sets the list of authority names that a [SecureServerSocket] will advertise
-   * as accepted when requesting a client certificate from a connecting
-   * client.
-   *
-   * [file] is a PEM or PKCS12 file containing the accepted signing
-   * authority certificates - the authority names are extracted from the
-   * certificates. For PKCS12 files, [password] is the password for the file.
-   * For PEM files, [password] is ignored. Assuming it is well-formatted, all
-   * other contents of [file] are ignored.
-   *
-   * NB: This function calls [File.readAsBytesSync], and will block on file IO.
-   * Prefer using [setClientAuthoritiesBytes].
-   *
-   * iOS note: This call is not supported.
-   */
+  /// Sets the list of authority names that a [SecureServerSocket] will advertise
+  /// as accepted when requesting a client certificate from a connecting
+  /// client.
+  ///
+  /// The [file] is a PEM or PKCS12 file containing the accepted signing
+  /// authority certificates - the authority names are extracted from the
+  /// certificates. For PKCS12 files, [password] is the password for the file.
+  /// For PEM files, [password] is ignored. Assuming it is well-formatted, all
+  /// other contents of [file] are ignored.
+  ///
+  /// NB: This function calls [File.readAsBytesSync], and will block on file IO.
+  /// Prefer using [setClientAuthoritiesBytes].
+  ///
+  /// iOS note: This call is not supported.
   void setClientAuthorities(String file, {String? password});
 
-  /**
-   * Sets the list of authority names that a [SecureServerSocket] will advertise
-   * as accepted, when requesting a client certificate from a connecting
-   * client.
-   *
-   * Like [setClientAuthorities] but takes the contents of the file.
-   */
+  /// Sets the list of authority names that a [SecureServerSocket] will advertise
+  /// as accepted, when requesting a client certificate from a connecting
+  /// client.
+  ///
+  /// Like [setClientAuthorities] but takes the contents of the file.
   void setClientAuthoritiesBytes(List<int> authCertBytes, {String? password});
 
-  /**
-   * Whether the platform supports ALPN. This always returns true and will be
-   * removed in a future release.
-   */
+  /// Whether the platform supports ALPN. This always returns true and will be
+  /// removed in a future release.
   @deprecated
   external static bool get alpnSupported;
 
-  /**
-   * Sets the list of application-level protocols supported by a client
-   * connection or server connection. The ALPN (application level protocol
-   * negotiation) extension to TLS allows a client to send a list of
-   * protocols in the TLS client hello message, and the server to pick
-   * one and send the selected one back in its server hello message.
-   *
-   * Separate lists of protocols can be sent for client connections and
-   * for server connections, using the same SecurityContext.  The [isServer]
-   * boolean argument specifies whether to set the list for server connections
-   * or client connections.
-   */
+  /// Sets the list of application-level protocols supported by a client
+  /// connection or server connection. The ALPN (application level protocol
+  /// negotiation) extension to TLS allows a client to send a list of
+  /// protocols in the TLS client hello message, and the server to pick
+  /// one and send the selected one back in its server hello message.
+  ///
+  /// Separate lists of protocols can be sent for client connections and
+  /// for server connections, using the same SecurityContext.  The [isServer]
+  /// boolean argument specifies whether to set the list for server connections
+  /// or client connections.
   void setAlpnProtocols(List<String> protocols, bool isServer);
 
   /// Encodes a set of supported protocols for ALPN/NPN usage.
   ///
-  /// The `protocols` list is expected to contain protocols in descending order
+  /// The [protocols] list is expected to contain protocols in descending order
   /// of preference.
   ///
   /// See RFC 7301 (https://tools.ietf.org/html/rfc7301) for the encoding of
   /// `List<String> protocols`:
-  ///     opaque ProtocolName<1..2^8-1>;
+  /// ```
+  /// opaque ProtocolName<1..2^8-1>;
   ///
-  ///     struct {
-  ///         ProtocolName protocol_name_list<2..2^16-1>
-  ///     } ProtocolNameList;
-  ///
+  /// struct {
+  ///     ProtocolName protocol_name_list<2..2^16-1>
+  /// } ProtocolNameList;
+  /// ```
   /// The encoding of the opaque `ProtocolName<lower..upper>` vector is
   /// described in RFC 2246: 4.3 Vectors.
   ///
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index ce5084a..a0eea00 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -4,12 +4,11 @@
 
 part of dart.io;
 
-/**
- * [InternetAddressType] is the type an [InternetAddress]. Currently,
- * IP version 4 (IPv4), IP version 6 (IPv6) and Unix domain address are
- * supported. Unix domain sockets are available only on Linux, MacOS and
- * Android.
- */
+/// The type, or address family, of an [InternetAddress].
+///
+/// Currently, IP version 4 (IPv4), IP version 6 (IPv6)
+/// and Unix domain address are supported.
+/// Unix domain sockets are available only on Linux, MacOS and Android.
 class InternetAddressType {
   static const InternetAddressType IPv4 = const InternetAddressType._(0);
   static const InternetAddressType IPv6 = const InternetAddressType._(1);
@@ -35,182 +34,139 @@
     throw new ArgumentError("Invalid type: $value");
   }
 
-  /**
-   * Get the name of the type, e.g. "IPv4" or "IPv6".
-   */
-  String get name {
-    switch (_value) {
-      case -1:
-        return "ANY";
-      case 0:
-        return "IPv4";
-      case 1:
-        return "IPv6";
-      case 2:
-        return "Unix";
-      default:
-        throw new ArgumentError("Invalid InternetAddress");
-    }
-  }
+  /// Get the name of the type, e.g. "IPv4" or "IPv6".
+  String get name => const ["ANY", "IPv4", "IPv6", "Unix"][_value + 1];
 
   String toString() => "InternetAddressType: $name";
 }
 
-/**
- * An internet address or a Unix domain address.
- *
- * This object holds an internet address. If this internet address
- * is the result of a DNS lookup, the address also holds the hostname
- * used to make the lookup.
- * An Internet address combined with a port number represents an
- * endpoint to which a socket can connect or a listening socket can
- * bind.
- */
+/// An internet address or a Unix domain address.
+///
+/// This object holds an internet address. If this internet address
+/// is the result of a DNS lookup, the address also holds the hostname
+/// used to make the lookup.
+/// An Internet address combined with a port number represents an
+/// endpoint to which a socket can connect or a listening socket can
+/// bind.
 abstract class InternetAddress {
-  /**
-   * IP version 4 loopback address. Use this address when listening on
-   * or connecting to the loopback adapter using IP version 4 (IPv4).
-   */
+  /// IP version 4 loopback address.
+  ///
+  /// Use this address when listening on or connecting
+  /// to the loopback adapter using IP version 4 (IPv4).
   static InternetAddress get loopbackIPv4 => LOOPBACK_IP_V4;
   @Deprecated("Use loopbackIPv4 instead")
   external static InternetAddress get LOOPBACK_IP_V4;
 
-  /**
-   * IP version 6 loopback address. Use this address when listening on
-   * or connecting to the loopback adapter using IP version 6 (IPv6).
-   */
+  /// IP version 6 loopback address.
+  ///
+  /// Use this address when listening on or connecting to
+  /// the loopback adapter using IP version 6 (IPv6).
   static InternetAddress get loopbackIPv6 => LOOPBACK_IP_V6;
   @Deprecated("Use loopbackIPv6 instead")
   external static InternetAddress get LOOPBACK_IP_V6;
 
-  /**
-   * IP version 4 any address. Use this address when listening on
-   * all adapters IP addresses using IP version 4 (IPv4).
-   */
+  /// IP version 4 any address.
+  ///
+  /// Use this address when listening on the addresses
+  /// of all adapters using IP version 4 (IPv4).
   static InternetAddress get anyIPv4 => ANY_IP_V4;
   @Deprecated("Use anyIPv4 instead")
   external static InternetAddress get ANY_IP_V4;
 
-  /**
-   * IP version 6 any address. Use this address when listening on
-   * all adapters IP addresses using IP version 6 (IPv6).
-   */
+  /// IP version 6 any address.
+  ///
+  /// Use this address when listening on the addresses
+  /// of all adapters using IP version 6 (IPv6).
   static InternetAddress get anyIPv6 => ANY_IP_V6;
   @Deprecated("Use anyIPv6 instead")
   external static InternetAddress get ANY_IP_V6;
 
-  /**
-   * The address family of the [InternetAddress].
-   */
+  /// The address family of the [InternetAddress].
   InternetAddressType get type;
 
-  /**
-   * The numeric address of the host.
-   *
-   * For IPv4 addresses this is using the dotted-decimal notation.
-   * For IPv6 it is using the hexadecimal representation.
-   * For Unix domain addresses, this is a file path.
-   */
+  /// The numeric address of the host.
+  ///
+  /// For IPv4 addresses this is using the dotted-decimal notation.
+  /// For IPv6 it is using the hexadecimal representation.
+  /// For Unix domain addresses, this is a file path.
   String get address;
 
-  /**
-   * The host used to lookup the address.
-   *
-   * If there is no host associated with the address this returns the [address].
-   */
+  /// The host used to lookup the address.
+  ///
+  /// If there is no host associated with the address this returns the [address].
   String get host;
 
-  /**
-   * The raw address of this [InternetAddress].
-   *
-   * For an IP address, the result is either a 4 or 16 byte long list.
-   * For a Unix domain address, UTF-8 encoded byte sequences that represents
-   * [address] is returned.
-   *
-   * The returned list is a fresh copy, making it possible to change the list without
-   * modifying the [InternetAddress].
-   */
+  /// The raw address of this [InternetAddress].
+  ///
+  /// For an IP address, the result is either a 4 or 16 byte long list.
+  /// For a Unix domain address, UTF-8 encoded byte sequences that represents
+  /// [address] is returned.
+  ///
+  /// The returned list is a fresh copy, making it possible to change the list without
+  /// modifying the [InternetAddress].
   Uint8List get rawAddress;
 
-  /**
-   * Returns true if the [InternetAddress] is a loopback address.
-   */
+  /// Whether the [InternetAddress] is a loopback address.
   bool get isLoopback;
 
-  /**
-   * Returns true if the [InternetAddress]s scope is a link-local.
-   */
+  /// Whether the scope of the [InternetAddress] is a link-local.
   bool get isLinkLocal;
 
-  /**
-   * Returns true if the [InternetAddress]s scope is multicast.
-   */
+  /// Whether the scope of the [InternetAddress] is multicast.
   bool get isMulticast;
 
-  /**
-   * Creates a new [InternetAddress] from a numeric address or a file path.
-   *
-   * If [type] is [InternetAddressType.IPv4], [address] must be a numeric IPv4
-   * address (dotted-decimal notation).
-   * If [type] is [InternetAddressType.IPv6], [address] must be a numeric IPv6
-   * address (hexadecimal notation).
-   * If [type] is [InternetAddressType.unix], [address] must be a a valid file
-   * path.
-   * If [type] is omitted, [address] must be either a numeric IPv4 or IPv6
-   * address and the type is inferred from the format.
-   *
-   * To create a Unix domain address, [type] should be
-   * [InternetAddressType.unix] and [address] should be a string.
-   */
+  /// Creates a new [InternetAddress] from a numeric address or a file path.
+  ///
+  /// If [type] is [InternetAddressType.IPv4], [address] must be a numeric IPv4
+  /// address (dotted-decimal notation).
+  /// If [type] is [InternetAddressType.IPv6], [address] must be a numeric IPv6
+  /// address (hexadecimal notation).
+  /// If [type] is [InternetAddressType.unix], [address] must be a a valid file
+  /// path.
+  /// If [type] is omitted, [address] must be either a numeric IPv4 or IPv6
+  /// address and the type is inferred from the format.
   external factory InternetAddress(String address,
       {@Since("2.8") InternetAddressType? type});
 
-  /**
-   * Creates a new [InternetAddress] from the provided raw address bytes.
-   *
-   * If the [type] is [InternetAddressType.IPv4], the [rawAddress] must have
-   * length 4.
-   * If the [type] is [InternetAddressType.IPv6], the [rawAddress] must have
-   * length 16.
-   * If the [type] is [InternetAddressType.unix], the [rawAddress] must be a
-   * valid UTF-8 encoded file path.
-   *
-   * If [type] is omitted, the [rawAddress] must have a length of either 4 or
-   * 16, in which case the type defaults to [InternetAddressType.IPv4] or
-   * [InternetAddressType.IPv6] respectively.
-   */
+  /// Creates a new [InternetAddress] from the provided raw address bytes.
+  ///
+  /// If the [type] is [InternetAddressType.IPv4], the [rawAddress] must have
+  /// length 4.
+  /// If the [type] is [InternetAddressType.IPv6], the [rawAddress] must have
+  /// length 16.
+  /// If the [type] is [InternetAddressType.unix], the [rawAddress] must be a
+  /// valid UTF-8 encoded file path.
+  ///
+  /// If [type] is omitted, the [rawAddress] must have a length of either 4 or
+  /// 16, in which case the type defaults to [InternetAddressType.IPv4] or
+  /// [InternetAddressType.IPv6] respectively.
   external factory InternetAddress.fromRawAddress(Uint8List rawAddress,
       {@Since("2.8") InternetAddressType? type});
 
-  /**
-   * Perform a reverse DNS lookup on this [address]
-   *
-   * Returns a new [InternetAddress] with the same address, but where the [host]
-   * field set to the result of the lookup.
-   *
-   * If this address is Unix domain addresses, no lookup is performed and this
-   * address is returned directly.
-   */
+  /// Performs a reverse DNS lookup on this [address]
+  ///
+  /// Returns a new [InternetAddress] with the same address, but where the [host]
+  /// field set to the result of the lookup.
+  ///
+  /// If this address is Unix domain addresses, no lookup is performed and this
+  /// address is returned directly.
   Future<InternetAddress> reverse();
 
-  /**
-   * Lookup a host, returning a Future of a list of
-   * [InternetAddress]s. If [type] is [InternetAddressType.ANY], it
-   * will lookup both IP version 4 (IPv4) and IP version 6 (IPv6)
-   * addresses. If [type] is either [InternetAddressType.IPv4] or
-   * [InternetAddressType.IPv6] it will only lookup addresses of the
-   * specified type. The order of the list can, and most likely will,
-   * change over time.
-   */
+  /// Looks up the addresses of a host.
+  ///
+  /// If [type] is [InternetAddressType.ANY], it will lookup both
+  /// IP version 4 (IPv4) and IP version 6 (IPv6) addresses.
+  /// If [type] is either [InternetAddressType.IPv4] or
+  /// [InternetAddressType.IPv6] it will only lookup addresses of the
+  /// specified type. The order of the list can, and most likely will,
+  /// change over time.
   external static Future<List<InternetAddress>> lookup(String host,
       {InternetAddressType type = InternetAddressType.any});
 
-  /**
-   * Clones the given [address] with the new [host].
-   *
-   * The [address] must be an [InternetAddress] that was created with one
-   * of the static methods of this class.
-   */
+  /// Clones the given [address] with the new [host].
+  ///
+  /// The [address] must be an [InternetAddress] that was created with one
+  /// of the static methods of this class.
   external static InternetAddress _cloneWithNewHost(
       InternetAddress address, String host);
 
@@ -221,166 +177,146 @@
   external static InternetAddress? tryParse(String address);
 }
 
-/**
- * A [NetworkInterface] represents an active network interface on the current
- * system. It contains a list of [InternetAddress]es that are bound to the
- * interface.
- */
+/// A [NetworkInterface] represents an active network interface on the current
+/// system. It contains a list of [InternetAddress]es that are bound to the
+/// interface.
 abstract class NetworkInterface {
-  /**
-   * Get the name of the [NetworkInterface].
-   */
+  /// The name of the [NetworkInterface].
   String get name;
 
-  /**
-   * Get the index of the [NetworkInterface].
-   */
+  /// The index of the [NetworkInterface].
   int get index;
 
-  /**
-   * Get a list of [InternetAddress]es currently bound to this
-   * [NetworkInterface].
-   */
+  /// The list of [InternetAddress]es currently bound to this
+  /// [NetworkInterface].
   List<InternetAddress> get addresses;
 
-  /**
-   * Whether [list] is supported.
-   *
-   * [list] is currently unsupported on Android.
-   */
+  /// Whether the [list] method is supported.
+  ///
+  /// The [list] method is currently unsupported on Android.
   external static bool get listSupported;
 
-  /**
-   * Query the system for [NetworkInterface]s.
-   *
-   * If [includeLoopback] is `true`, the returned list will include the
-   * loopback device. Default is `false`.
-   *
-   * If [includeLinkLocal] is `true`, the list of addresses of the returned
-   * [NetworkInterface]s, may include link local addresses. Default is `false`.
-   *
-   * If [type] is either [InternetAddressType.IPv4] or
-   * [InternetAddressType.IPv6] it will only lookup addresses of the
-   * specified type. Default is [InternetAddressType.any].
-   */
+  /// Query the system for [NetworkInterface]s.
+  ///
+  /// If [includeLoopback] is `true`, the returned list will include the
+  /// loopback device. Default is `false`.
+  ///
+  /// If [includeLinkLocal] is `true`, the list of addresses of the returned
+  /// [NetworkInterface]s, may include link local addresses. Default is `false`.
+  ///
+  /// If [type] is either [InternetAddressType.IPv4] or
+  /// [InternetAddressType.IPv6] it will only lookup addresses of the
+  /// specified type. Default is [InternetAddressType.any].
   external static Future<List<NetworkInterface>> list(
       {bool includeLoopback = false,
       bool includeLinkLocal = false,
       InternetAddressType type = InternetAddressType.any});
 }
 
-/**
- * A [RawServerSocket] represents a listening socket, and provides a
- * stream of low-level [RawSocket] objects, one for each connection
- * made to the listening socket.
- *
- * See [RawSocket] for more info.
- */
+/// A listening socket.
+///
+/// A `RawServerSocket` and provides a stream of low-level [RawSocket] objects,
+/// one for each connection made to the listening socket.
+///
+/// See [RawSocket] for more info.
 abstract class RawServerSocket implements Stream<RawSocket> {
-  /**
-   * Returns a future for a [:RawServerSocket:]. When the future
-   * completes the server socket is bound to the given [address] and
-   * [port] and has started listening on it.
-   *
-   * The [address] can either be a [String] or an
-   * [InternetAddress]. If [address] is a [String], [bind] will
-   * perform a [InternetAddress.lookup] and use the first value in the
-   * list. To listen on the loopback adapter, which will allow only
-   * incoming connections from the local host, use the value
-   * [InternetAddress.loopbackIPv4] or
-   * [InternetAddress.loopbackIPv6]. To allow for incoming
-   * connection from the network use either one of the values
-   * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
-   * bind to all interfaces or the IP address of a specific interface.
-   *
-   * If an IP version 6 (IPv6) address is used, both IP version 6
-   * (IPv6) and version 4 (IPv4) connections will be accepted. To
-   * restrict this to version 6 (IPv6) only, use [v6Only] to set
-   * version 6 only.
-   *
-   * If [port] has the value [:0:] an ephemeral port will
-   * be chosen by the system. The actual port used can be retrieved
-   * using the [:port:] getter.
-   *
-   * The optional argument [backlog] can be used to specify the listen
-   * backlog for the underlying OS listen setup. If [backlog] has the
-   * value of [:0:] (the default) a reasonable value will be chosen by
-   * the system.
-   *
-   * The optional argument [shared] specifies whether additional RawServerSocket
-   * objects can bind to the same combination of `address`, `port` and `v6Only`.
-   * If `shared` is `true` and more `RawServerSocket`s from this isolate or
-   * other isolates are bound to the port, then the incoming connections will be
-   * distributed among all the bound `RawServerSocket`s. Connections can be
-   * distributed over multiple isolates this way.
-   */
+  /// Listens on a given address and port.
+  ///
+  /// When the returned future completes the server socket is bound
+  /// to the given [address] and [port] and has started listening on it.
+  ///
+  /// The [address] can either be a [String] or an
+  /// [InternetAddress]. If [address] is a [String], [bind] will
+  /// perform a [InternetAddress.lookup] and use the first value in the
+  /// list. To listen on the loopback adapter, which will allow only
+  /// incoming connections from the local host, use the value
+  /// [InternetAddress.loopbackIPv4] or
+  /// [InternetAddress.loopbackIPv6]. To allow for incoming
+  /// connection from the network use either one of the values
+  /// [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+  /// bind to all interfaces or the IP address of a specific interface.
+  ///
+  /// If an IP version 6 (IPv6) address is used, both IP version 6
+  /// (IPv6) and version 4 (IPv4) connections will be accepted. To
+  /// restrict this to version 6 (IPv6) only, use [v6Only] to set
+  /// version 6 only.
+  ///
+  /// If [port] has the value `0` an ephemeral port will
+  /// be chosen by the system. The actual port used can be retrieved
+  /// using the `port` getter.
+  ///
+  /// The optional argument [backlog] can be used to specify the listen
+  /// backlog for the underlying OS listen setup. If [backlog] has the
+  /// value of `0` (the default) a reasonable value will be chosen by
+  /// the system.
+  ///
+  /// The optional argument [shared] specifies whether additional RawServerSocket
+  /// objects can bind to the same combination of [address], [port] and [v6Only].
+  /// If [shared] is `true` and more [RawServerSocket]s from this isolate or
+  /// other isolates are bound to the port, then the incoming connections will be
+  /// distributed among all the bound [RawServerSocket]s. Connections can be
+  /// distributed over multiple isolates this way.
   external static Future<RawServerSocket> bind(address, int port,
       {int backlog = 0, bool v6Only = false, bool shared = false});
 
-  /**
-   * Returns the port used by this socket.
-   */
+  /// The port used by this socket.
   int get port;
 
-  /**
-   * Returns the address used by this socket.
-   */
+  /// The address used by this socket.
   InternetAddress get address;
 
-  /**
-   * Closes the socket. The returned future completes when the socket
-   * is fully closed and is no longer bound.
-   */
+  /// Closes the socket.
+  ///
+  /// The returned future completes when the socket
+  /// is fully closed and is no longer bound.
   Future<RawServerSocket> close();
 }
 
-/**
- * A [ServerSocket] represents a listening socket, and provides a
- * stream of [Socket] objects, one for each connection made to the
- * listening socket.
- *
- * See [Socket] for more info.
- */
+/// A listening socket.
+///
+/// A [ServerSocket] provides a stream of [Socket] objects,
+/// one for each connection made to the listening socket.
+///
+/// See [Socket] for more info.
 abstract class ServerSocket implements Stream<Socket> {
-  /**
-   * Returns a future for a [:ServerSocket:]. When the future
-   * completes the server socket is bound to the given [address] and
-   * [port] and has started listening on it.
-   *
-   * The [address] can either be a [String] or an
-   * [InternetAddress]. If [address] is a [String], [bind] will
-   * perform a [InternetAddress.lookup] and use the first value in the
-   * list. To listen on the loopback adapter, which will allow only
-   * incoming connections from the local host, use the value
-   * [InternetAddress.loopbackIPv4] or
-   * [InternetAddress.loopbackIPv6]. To allow for incoming
-   * connection from the network use either one of the values
-   * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
-   * bind to all interfaces or the IP address of a specific interface.
-   *
-   * If an IP version 6 (IPv6) address is used, both IP version 6
-   * (IPv6) and version 4 (IPv4) connections will be accepted. To
-   * restrict this to version 6 (IPv6) only, use [v6Only] to set
-   * version 6 only.
-   *
-   * If [port] has the value [:0:] an ephemeral port will be chosen by
-   * the system. The actual port used can be retrieved using the
-   * [port] getter.
-   *
-   * The optional argument [backlog] can be used to specify the listen
-   * backlog for the underlying OS listen setup. If [backlog] has the
-   * value of [:0:] (the default) a reasonable value will be chosen by
-   * the system.
-   *
-   * The optional argument [shared] specifies whether additional ServerSocket
-   * objects can bind to the same combination of `address`, `port` and `v6Only`.
-   * If `shared` is `true` and more `ServerSocket`s from this isolate or other
-   * isolates are bound to the port, then the incoming connections will be
-   * distributed among all the bound `ServerSocket`s. Connections can be
-   * distributed over multiple isolates this way.
-   */
+  /// Listens on a given address and port.
+  ///
+  /// When the returned future completes the server socket is bound
+  /// to the given [address] and [port] and has started listening on it.
+  ///
+  /// The [address] can either be a [String] or an
+  /// [InternetAddress]. If [address] is a [String], [bind] will
+  /// perform a [InternetAddress.lookup] and use the first value in the
+  /// list. To listen on the loopback adapter, which will allow only
+  /// incoming connections from the local host, use the value
+  /// [InternetAddress.loopbackIPv4] or
+  /// [InternetAddress.loopbackIPv6]. To allow for incoming
+  /// connection from the network use either one of the values
+  /// [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+  /// bind to all interfaces or the IP address of a specific interface.
+  ///
+  /// If an IP version 6 (IPv6) address is used, both IP version 6
+  /// (IPv6) and version 4 (IPv4) connections will be accepted. To
+  /// restrict this to version 6 (IPv6) only, use [v6Only] to set
+  /// version 6 only.
+  ///
+  /// If [port] has the value `0` an ephemeral port will be chosen by
+  /// the system. The actual port used can be retrieved using the
+  /// [port] getter.
+  ///
+  /// The optional argument [backlog] can be used to specify the listen
+  /// backlog for the underlying OS listen setup. If [backlog] has the
+  /// value of `0` (the default) a reasonable value will be chosen by
+  /// the system.
+  ///
+  /// The optional argument [shared] specifies whether additional ServerSocket
+  /// objects can bind to the same combination of [address], [port] [and] [v6Only].
+  /// If [shared] is `true` and more [ServerSockets] from this isolate or other
+  /// isolates are bound to the port, then the incoming connections will be
+  /// distributed among all the bound [ServerSockets]. Connections can be
+  /// distributed over multiple isolates this way.
   static Future<ServerSocket> bind(address, int port,
-      {int backlog: 0, bool v6Only: false, bool shared: false}) {
+      {int backlog = 0, bool v6Only = false, bool shared = false}) {
     final IOOverrides? overrides = IOOverrides.current;
     if (overrides == null) {
       return ServerSocket._bind(address, port,
@@ -393,27 +329,21 @@
   external static Future<ServerSocket> _bind(address, int port,
       {int backlog = 0, bool v6Only = false, bool shared = false});
 
-  /**
-   * Returns the port used by this socket.
-   */
+  /// The port used by this socket.
   int get port;
 
-  /**
-   * Returns the address used by this socket.
-   */
+  /// The address used by this socket.
   InternetAddress get address;
 
-  /**
-   * Closes the socket. The returned future completes when the socket
-   * is fully closed and is no longer bound.
-   */
+  /// Closes the socket.
+  ///
+  /// The returned future completes when the socket
+  /// is fully closed and is no longer bound.
   Future<ServerSocket> close();
 }
 
-/**
- * The [SocketDirection] is used as a parameter to [Socket.close] and
- * [RawSocket.close] to close a socket in the specified direction(s).
- */
+/// The [SocketDirection] is used as a parameter to [Socket.close] and
+/// [RawSocket.close] to close a socket in the specified direction(s).
 class SocketDirection {
   static const SocketDirection receive = const SocketDirection._(0);
   static const SocketDirection send = const SocketDirection._(1);
@@ -431,19 +361,17 @@
   const SocketDirection._(this._value);
 }
 
-/**
- * The [SocketOption] is used as a parameter to [Socket.setOption] and
- * [RawSocket.setOption] to customize the behaviour of the underlying
- * socket.
- */
+/// An option for a socket which is configured using [Socket.setOption].
+///
+/// The [SocketOption] is used as a parameter to [Socket.setOption] and
+/// [RawSocket.setOption] to customize the behaviour of the underlying
+/// socket.
 class SocketOption {
-  /**
-   * Enable or disable no-delay on the socket. If tcpNoDelay is enabled, the
-   * socket will not buffer data internally, but instead write each data chunk
-   * as an individual TCP packet.
-   *
-   * tcpNoDelay is disabled by default.
-   */
+  /// Enable or disable no-delay on the socket. If tcpNoDelay is enabled, the
+  /// socket will not buffer data internally, but instead write each data chunk
+  /// as an individual TCP packet.
+  ///
+  /// tcpNoDelay is disabled by default.
   static const SocketOption tcpNoDelay = const SocketOption._(0);
   @Deprecated("Use tcpNoDelay instead")
   static const SocketOption TCP_NODELAY = tcpNoDelay;
@@ -478,10 +406,11 @@
 /// getsockopt.
 @Since("2.2")
 class RawSocketOption {
-  /// Creates a RawSocketOption for getRawOption andSetRawOption.
+  /// Creates a [RawSocketOption] for [RawSocket.getRawOption]
+  /// and [RawSocket.setRawOption].
   ///
-  /// The level and option arguments correspond to level and optname arguments
-  /// on the getsockopt and setsockopt native calls.
+  /// The [level] and [option] arguments correspond to `level` and `optname` arguments
+  /// on the `getsockopt()` and `setsockopt()` native calls.
   ///
   /// The value argument and its length correspond to the optval and length
   /// arguments on the native call.
@@ -493,7 +422,7 @@
   /// the option.
   const RawSocketOption(this.level, this.option, this.value);
 
-  /// Convenience constructor for creating an int based RawSocketOption.
+  /// Convenience constructor for creating an integer based [RawSocketOption].
   factory RawSocketOption.fromInt(int level, int option, int value) {
     final Uint8List list = Uint8List(4);
     final buffer = ByteData.view(list.buffer, list.offsetInBytes);
@@ -501,7 +430,7 @@
     return RawSocketOption(level, option, list);
   }
 
-  /// Convenience constructor for creating a bool based RawSocketOption.
+  /// Convenience constructor for creating a boolean based [RawSocketOption].
   factory RawSocketOption.fromBool(int level, int option, bool value) =>
       RawSocketOption.fromInt(level, option, value ? 1 : 0);
 
@@ -515,54 +444,53 @@
   ///   * [RawSocketOption.levelUdp]
   final int level;
 
-  /// The option to set or get.
+  /// The numeric ID of the option to set or get.
   final int option;
 
   /// The raw data to set, or the array to write the current option value into.
   ///
   /// This list must be the correct length for the expected option. For most
-  /// options that take int or bool values, the length should be 4. For options
+  /// options that take [int] or [bool] values, the length should be 4. For options
   /// that expect a struct (such as an in_addr_t), the length should be the
   /// correct length for that struct.
   final Uint8List value;
 
-  /// Socket level option for SOL_SOCKET.
+  /// Socket level option for `SOL_SOCKET`.
   static int get levelSocket =>
       _getOptionValue(_RawSocketOptions.SOL_SOCKET.index);
 
-  /// Socket level option for IPPROTO_IP.
+  /// Socket level option for `IPPROTO_IP`.
   static int get levelIPv4 =>
       _getOptionValue(_RawSocketOptions.IPPROTO_IP.index);
 
-  /// Socket option for IP_MULTICAST_IF.
+  /// Socket option for `IP_MULTICAST_IF`.
   static int get IPv4MulticastInterface =>
       _getOptionValue(_RawSocketOptions.IP_MULTICAST_IF.index);
 
-  /// Socket level option for IPPROTO_IPV6.
+  /// Socket level option for `IPPROTO_IPV6`.
   static int get levelIPv6 =>
       _getOptionValue(_RawSocketOptions.IPPROTO_IPV6.index);
 
-  /// Socket option for IPV6_MULTICAST_IF.
+  /// Socket option for `IPV6_MULTICAST_IF`.
   static int get IPv6MulticastInterface =>
       _getOptionValue(_RawSocketOptions.IPV6_MULTICAST_IF.index);
 
-  /// Socket level option for IPPROTO_TCP.
+  /// Socket level option for `IPPROTO_TCP`.
   static int get levelTcp =>
       _getOptionValue(_RawSocketOptions.IPPROTO_TCP.index);
 
-  /// Socket level option for IPPROTO_UDP.
+  /// Socket level option for `IPPROTO_UDP`.
   static int get levelUdp =>
       _getOptionValue(_RawSocketOptions.IPPROTO_UDP.index);
 
   external static int _getOptionValue(int key);
 }
 
-/**
- * Events for the [RawSocket].
- *
- * These event objects are by the [Stream] behavior of [RawSocket] (for example
- * [RawSocket.listen], [RawSocket.forEach]) when the socket's state change.
- */
+/// Events for the [RawSocket].
+///
+/// These event objects are used by the [Stream] behavior of [RawSocket]
+/// (for example [RawSocket.listen], [RawSocket.forEach])
+/// when the socket's state change.
 class RawSocketEvent {
   /// An event indicates the socket is ready to be read.
   static const RawSocketEvent read = const RawSocketEvent._(0);
@@ -598,13 +526,15 @@
   }
 }
 
+/// A cancelable connection attempt.
+///
 /// Returned by the `startConnect` methods on client-side socket types `S`,
 /// `ConnectionTask<S>` allows cancelling an attempt to connect to a host.
 class ConnectionTask<S> {
   /// A `Future` that completes with value that `S.connect()` would return
   /// unless [cancel] is called on this [ConnectionTask].
   ///
-  /// If [cancel] is called, the `Future` completes with a [SocketException]
+  /// If [cancel] is called, the future completes with a [SocketException]
   /// error whose message indicates that the connection attempt was cancelled.
   final Future<S> socket;
   final void Function() _onCancel;
@@ -633,44 +563,37 @@
 /// ([RawSocketEvent.read]) or when the remote end has stopped listening
 /// ([RawSocketEvent.closed]).
 abstract class RawSocket implements Stream<RawSocketEvent> {
-  /**
-   * Set or get, if the [RawSocket] should listen for [RawSocketEvent.read]
-   * events. Default is [:true:].
-   */
-  bool get readEventsEnabled;
-  void set readEventsEnabled(bool value);
+  /// Set or get, if the [RawSocket] should listen for [RawSocketEvent.read]
+  /// events. Default is `true`.
+  abstract bool readEventsEnabled;
 
-  /**
-   * Set or get, if the [RawSocket] should listen for [RawSocketEvent.write]
-   * events. Default is [:true:].
-   * This is a one-shot listener, and writeEventsEnabled must be set
-   * to true again to receive another write event.
-   */
-  bool get writeEventsEnabled;
-  void set writeEventsEnabled(bool value);
+  /// Set or get, if the [RawSocket] should listen for [RawSocketEvent.write]
+  /// events. Default is `true`.
+  /// This is a one-shot listener, and writeEventsEnabled must be set
+  /// to true again to receive another write event.
+  abstract bool writeEventsEnabled;
 
-  /**
-   * Creates a new socket connection to the host and port and returns a [Future]
-   * that will complete with either a [RawSocket] once connected or an error
-   * if the host-lookup or connection failed.
-   *
-   * [host] can either be a [String] or an [InternetAddress]. If [host] is a
-   * [String], [connect] will perform a [InternetAddress.lookup] and try
-   * all returned [InternetAddress]es, until connected. Unless a
-   * connection was established, the error from the first failing connection is
-   * returned.
-   *
-   * The argument [sourceAddress] can be used to specify the local
-   * address to bind when making the connection. `sourceAddress` can either
-   * be a `String` or an `InternetAddress`. If a `String` is passed it must
-   * hold a numeric IP address.
-   *
-   * The argument [timeout] is used to specify the maximum allowed time to wait
-   * for a connection to be established. If [timeout] is longer than the system
-   * level timeout duration, a timeout may occur sooner than specified in
-   * [timeout]. On timeout, a [SocketException] is thrown and all ongoing
-   * connection attempts to [host] are cancelled.
-   */
+  /// Creates a new socket connection to the host and port.
+  ///
+  /// Returns a [Future] that will complete with either a [RawSocket]
+  /// once connected, or an error if the host-lookup or connection failed.
+  ///
+  /// The [host] can either be a [String] or an [InternetAddress]. If [host] is a
+  /// [String], [connect] will perform a [InternetAddress.lookup] and try
+  /// all returned [InternetAddress]es, until connected. Unless a
+  /// connection was established, the error from the first failing connection is
+  /// returned.
+  ///
+  /// The argument [sourceAddress] can be used to specify the local
+  /// address to bind when making the connection. The [sourceAddress] can either
+  /// be a [String] or an [InternetAddress]. If a [String] is passed it must
+  /// hold a numeric IP address.
+  ///
+  /// The argument [timeout] is used to specify the maximum allowed time to wait
+  /// for a connection to be established. If [timeout] is longer than the system
+  /// level timeout duration, a timeout may occur sooner than specified in
+  /// [timeout]. On timeout, a [SocketException] is thrown and all ongoing
+  /// connection attempts to [host] are cancelled.
   external static Future<RawSocket> connect(host, int port,
       {sourceAddress, Duration? timeout});
 
@@ -680,103 +603,89 @@
   external static Future<ConnectionTask<RawSocket>> startConnect(host, int port,
       {sourceAddress});
 
-  /**
-   * Returns the number of received and non-read bytes in the socket that
-   * can be read.
-   */
+  /// The number of received and non-read bytes in the socket that can be read.
   int available();
 
-  /**
-   * Read up to [len] bytes from the socket. This function is
-   * non-blocking and will only return data if data is available. The
-   * number of bytes read can be less then [len] if fewer bytes are
-   * available for immediate reading. If no data is available [:null:]
-   * is returned.
-   */
+  /// Read up to [len] bytes from the socket.
+  ///
+  /// This function is non-blocking and will only return data
+  /// if data is available.
+  /// The number of bytes read can be less then [len] if fewer bytes are
+  /// available for immediate reading. If no data is available `null`
+  /// is returned.
   Uint8List? read([int? len]);
 
-  /**
-   * Writes up to [count] bytes of the buffer from [offset] buffer offset to
-   * the socket. The number of successfully written bytes is returned. This
-   * function is non-blocking and will only write data if buffer space is
-   * available in the socket.
-   *
-   * The default value for [offset] is 0, and the default value for [count] is
-   * [:buffer.length - offset:].
-   */
+  /// Writes up to [count] bytes of the buffer from [offset] buffer offset to
+  /// the socket.
+  ///
+  /// The number of successfully written bytes is returned.
+  /// This function is non-blocking and will only write data
+  /// if buffer space is available in the socket.
+  ///
+  /// The default value for [offset] is 0, and the default value for [count] is
+  /// `buffer.length - offset`.
   int write(List<int> buffer, [int offset = 0, int? count]);
 
-  /**
-   * Returns the port used by this socket.
-   *
-   * Throws a [SocketException] if the socket is closed.
-   */
+  /// The port used by this socket.
+  ///
+  /// Throws a [SocketException] if the socket is closed.
   int get port;
 
-  /**
-   * Returns the remote port connected to by this socket.
-   *
-   * Throws a [SocketException] if the socket is closed.
-   */
+  /// The remote port connected to by this socket.
+  ///
+  /// Throws a [SocketException] if the socket is closed.
   int get remotePort;
 
-  /**
-   * Returns the [InternetAddress] used to connect this socket.
-   *
-   * Throws a [SocketException] if the socket is closed.
-   */
+  /// The [InternetAddress] used to connect this socket.
+  ///
+  /// Throws a [SocketException] if the socket is closed.
   InternetAddress get address;
 
-  /**
-   * Returns the remote [InternetAddress] connected to by this socket.
-   *
-   * Throws a [SocketException] if the socket is closed.
-   */
+  /// The remote [InternetAddress] connected to by this socket.
+  ///
+  /// Throws a [SocketException] if the socket is closed.
   InternetAddress get remoteAddress;
 
-  /**
-   * Closes the socket. Returns a Future that completes with [this] when the
-   * underlying connection is completely destroyed.
-   *
-   * Calling [close] will never throw an exception
-   * and calling it several times is supported. Calling [close] can result in
-   * a [RawSocketEvent.readClosed] event.
-   */
+  /// Closes the socket.
+  ///
+  /// Returns a future that completes with this socket when the
+  /// underlying connection is completely destroyed.
+  ///
+  /// Calling [close] will never throw an exception
+  /// and calling it several times is supported. Calling [close] can result in
+  /// a [RawSocketEvent.readClosed] event.
   Future<RawSocket> close();
 
-  /**
-   * Shutdown the socket in the [direction]. Calling [shutdown] will never
-   * throw an exception and calling it several times is supported. Calling
-   * shutdown with either [SocketDirection.both] or [SocketDirection.receive]
-   * can result in a [RawSocketEvent.readClosed] event.
-   */
+  /// Shuts down the socket in the [direction].
+  ///
+  /// Calling [shutdown] will never throw an exception
+  /// and calling it several times is supported. Calling
+  /// shutdown with either [SocketDirection.both] or [SocketDirection.receive]
+  /// can result in a [RawSocketEvent.readClosed] event.
   void shutdown(SocketDirection direction);
 
-  /**
-   * Use [setOption] to customize the [RawSocket]. See [SocketOption] for
-   * available options.
-   *
-   * Returns [:true:] if the option was set successfully, false otherwise.
-   */
+  /// Customize the [RawSocket].
+  ///
+  /// See [SocketOption] for available options.
+  ///
+  /// Returns `true` if the option was set successfully, `false` otherwise.
   bool setOption(SocketOption option, bool enabled);
 
-  /**
-   * Use [getRawOption] to get low level information about the [RawSocket]. See
-   * [RawSocketOption] for available options.
-   *
-   * Returns the [RawSocketOption.value] on success.
-   *
-   * Throws an [OSError] on failure.
-   */
+  /// Reads low level information about the [RawSocket].
+  ///
+  /// See [RawSocketOption] for available options.
+  ///
+  /// Returns the [RawSocketOption.value] on success.
+  ///
+  /// Throws an [OSError] on failure.
   @Since("2.2")
   Uint8List getRawOption(RawSocketOption option);
 
-  /**
-   * Use [setRawOption] to customize the [RawSocket]. See [RawSocketOption] for
-   * available options.
-   *
-   * Throws an [OSError] on failure.
-   */
+  /// Customizes the [RawSocket].
+  ///
+  /// See [RawSocketOption] for available options.
+  ///
+  /// Throws an [OSError] on failure.
   @Since("2.2")
   void setRawOption(RawSocketOption option);
 }
@@ -788,28 +697,26 @@
 /// by the [Stream] interface of this class, and can be sent to the remote
 /// socket through the [IOSink] interface of this class.
 abstract class Socket implements Stream<Uint8List>, IOSink {
-  /**
-   * Creates a new socket connection to the host and port and returns a [Future]
-   * that will complete with either a [Socket] once connected or an error
-   * if the host-lookup or connection failed.
-   *
-   * [host] can either be a [String] or an [InternetAddress]. If [host] is a
-   * [String], [connect] will perform a [InternetAddress.lookup] and try
-   * all returned [InternetAddress]es, until connected. Unless a
-   * connection was established, the error from the first failing connection is
-   * returned.
-   *
-   * The argument [sourceAddress] can be used to specify the local
-   * address to bind when making the connection. `sourceAddress` can either
-   * be a `String` or an `InternetAddress`. If a `String` is passed it must
-   * hold a numeric IP address.
-   *
-   * The argument [timeout] is used to specify the maximum allowed time to wait
-   * for a connection to be established. If [timeout] is longer than the system
-   * level timeout duration, a timeout may occur sooner than specified in
-   * [timeout]. On timeout, a [SocketException] is thrown and all ongoing
-   * connection attempts to [host] are cancelled.
-   */
+  /// Creates a new socket connection to the host and port and returns a [Future]
+  /// that will complete with either a [Socket] once connected or an error
+  /// if the host-lookup or connection failed.
+  ///
+  /// [host] can either be a [String] or an [InternetAddress]. If [host] is a
+  /// [String], [connect] will perform a [InternetAddress.lookup] and try
+  /// all returned [InternetAddress]es, until connected. Unless a
+  /// connection was established, the error from the first failing connection is
+  /// returned.
+  ///
+  /// The argument [sourceAddress] can be used to specify the local
+  /// address to bind when making the connection. The [sourceAddress] can either
+  /// be a [String] or an [InternetAddress]. If a [String] is passed it must
+  /// hold a numeric IP address.
+  ///
+  /// The argument [timeout] is used to specify the maximum allowed time to wait
+  /// for a connection to be established. If [timeout] is longer than the system
+  /// level timeout duration, a timeout may occur sooner than specified in
+  /// [timeout]. On timeout, a [SocketException] is thrown and all ongoing
+  /// connection attempts to [host] are cancelled.
   static Future<Socket> connect(host, int port,
       {sourceAddress, Duration? timeout}) {
     final IOOverrides? overrides = IOOverrides.current;
@@ -840,75 +747,63 @@
   external static Future<ConnectionTask<Socket>> _startConnect(host, int port,
       {sourceAddress});
 
-  /**
-   * Destroy the socket in both directions. Calling [destroy] will make the
-   * send a close event on the stream and will no longer react on data being
-   * piped to it.
-   *
-   * Call [close](inherited from [IOSink]) to only close the [Socket]
-   * for sending data.
-   */
+  /// Destroys the socket in both directions.
+  ///
+  /// Calling [destroy] will make the send a close event on the stream
+  /// and will no longer react on data being piped to it.
+  ///
+  /// Call [close] (inherited from [IOSink]) to only close the [Socket]
+  /// for sending data.
   void destroy();
 
-  /**
-   * Use [setOption] to customize the [RawSocket]. See [SocketOption] for
-   * available options.
-   *
-   * Returns [:true:] if the option was set successfully, false otherwise.
-   *
-   * Throws a [SocketException] if the socket has been destroyed or upgraded to
-   * a secure socket.
-   */
+  /// Customizes the [RawSocket].
+  ///
+  /// See [SocketOption] for available options.
+  ///
+  /// Returns `true` if the option was set successfully, false otherwise.
+  ///
+  /// Throws a [SocketException] if the socket has been destroyed or upgraded to
+  /// a secure socket.
   bool setOption(SocketOption option, bool enabled);
 
-  /**
-   * Use [getRawOption] to get low level information about the [RawSocket]. See
-   * [RawSocketOption] for available options.
-   *
-   * Returns the [RawSocketOption.value] on success.
-   *
-   * Throws an [OSError] on failure and a [SocketException] if the socket has
-   * been destroyed or upgraded to a secure socket.
-   */
+  /// Reads low level information about the [RawSocket].
+  ///
+  /// See [RawSocketOption] for available options.
+  ///
+  /// Returns the [RawSocketOption.value] on success.
+  ///
+  /// Throws an [OSError] on failure and a [SocketException] if the socket has
+  /// been destroyed or upgraded to a secure socket.
   Uint8List getRawOption(RawSocketOption option);
 
-  /**
-   * Use [setRawOption] to customize the [RawSocket]. See [RawSocketOption] for
-   * available options.
-   *
-   * Throws an [OSError] on failure and a [SocketException] if the socket has
-   * been destroyed or upgraded to a secure socket.
-   */
+  /// Customizes the [RawSocket].
+  ///
+  /// See [RawSocketOption] for available options.
+  ///
+  /// Throws an [OSError] on failure and a [SocketException] if the socket has
+  /// been destroyed or upgraded to a secure socket.
   void setRawOption(RawSocketOption option);
 
-  /**
-   * The port used by this socket.
-   *
-   * Throws a [SocketException] if the socket is closed.
-   * The port is 0 if the socket is a Unix domain socket.
-   */
+  /// The port used by this socket.
+  ///
+  /// Throws a [SocketException] if the socket is closed.
+  /// The port is 0 if the socket is a Unix domain socket.
   int get port;
 
-  /**
-   * The remote port connected to by this socket.
-   *
-   * Throws a [SocketException] if the socket is closed.
-   * The port is 0 if the socket is a Unix domain socket.
-   */
+  /// The remote port connected to by this socket.
+  ///
+  /// Throws a [SocketException] if the socket is closed.
+  /// The port is 0 if the socket is a Unix domain socket.
   int get remotePort;
 
-  /**
-   * The [InternetAddress] used to connect this socket.
-   *
-   * Throws a [SocketException] if the socket is closed.
-   */
+  /// The [InternetAddress] used to connect this socket.
+  ///
+  /// Throws a [SocketException] if the socket is closed.
   InternetAddress get address;
 
-  /**
-   * The remote [InternetAddress] connected to by this socket.
-   *
-   * Throws a [SocketException] if the socket is closed.
-   */
+  /// The remote [InternetAddress] connected to by this socket.
+  ///
+  /// Throws a [SocketException] if the socket is closed.
   InternetAddress get remoteAddress;
 
   Future close();
@@ -916,7 +811,7 @@
   Future get done;
 }
 
-/// A data packet which is received by a [RawDatagramSocket].
+/// A data packet received by a [RawDatagramSocket].
 class Datagram {
   /// The actual bytes of the message.
   Uint8List data;
@@ -930,167 +825,135 @@
   Datagram(this.data, this.address, this.port);
 }
 
-/**
- * A [RawDatagramSocket] is an unbuffered interface to a UDP socket.
- *
- * The raw datagram socket delivers the datagrams in the same chunks as the
- * underlying operating system. It's a [Stream] of [RawSocketEvent]s.
- *
- * Note that the event [RawSocketEvent.readClosed] will never be
- * received as an UDP socket cannot be closed by a remote peer.
- *
- * It is not the same as a
- * [POSIX raw socket](http://man7.org/linux/man-pages/man7/raw.7.html).
- */
+/// An unbuffered interface to a UDP socket.
+///
+/// The raw datagram socket delivers the datagrams in the same chunks as the
+/// underlying operating system. It's a [Stream] of [RawSocketEvent]s.
+///
+/// Note that the event [RawSocketEvent.readClosed] will never be
+/// received as an UDP socket cannot be closed by a remote peer.
+///
+/// It is not the same as a
+/// [POSIX raw socket](http://man7.org/linux/man-pages/man7/raw.7.html).
 abstract class RawDatagramSocket extends Stream<RawSocketEvent> {
-  /**
-   * Set or get, if the [RawDatagramSocket] should listen for
-   * [RawSocketEvent.read] events. Default is [:true:].
-   */
-  bool get readEventsEnabled;
-  void set readEventsEnabled(bool value);
+  /// Whether the [RawDatagramSocket] should listen for
+  /// [RawSocketEvent.read] events.
+  ///
+  /// Default is `true`.
+  abstract bool readEventsEnabled;
 
-  /**
-   * Set or get, if the [RawDatagramSocket] should listen for
-   * [RawSocketEvent.write] events. Default is [:true:].  This is a
-   * one-shot listener, and writeEventsEnabled must be set to true
-   * again to receive another write event.
-   */
-  bool get writeEventsEnabled;
-  void set writeEventsEnabled(bool value);
+  /// Whether the [RawDatagramSocket] should listen for
+  /// [RawSocketEvent.write] events.
+  ///
+  /// Default is `true`.
+  /// This is a one-shot listener, and [writeEventsEnabled] must be set to true
+  /// again to receive another write event.
+  abstract bool writeEventsEnabled;
 
-  /**
-   * Set or get, whether multicast traffic is looped back to the host.
-   *
-   * By default multicast loopback is enabled.
-   */
-  bool get multicastLoopback;
-  void set multicastLoopback(bool value);
+  /// Whether multicast traffic is looped back to the host.
+  ///
+  /// By default multicast loopback is enabled.
+  abstract bool multicastLoopback;
 
-  /**
-   * Set or get, the maximum network hops for multicast packages
-   * originating from this socket.
-   *
-   * For IPv4 this is referred to as TTL (time to live).
-   *
-   * By default this value is 1 causing multicast traffic to stay on
-   * the local network.
-   */
-  int get multicastHops;
-  void set multicastHops(int value);
+  /// The maximum network hops for multicast packages
+  /// originating from this socket.
+  ///
+  /// For IPv4 this is referred to as TTL (time to live).
+  ///
+  /// By default this value is 1 causing multicast traffic to stay on
+  /// the local network.
+  abstract int multicastHops;
 
-  /**
-   * Set or get, the network interface used for outgoing multicast packages.
-   *
-   * A value of `null`indicate that the system chooses the network
-   * interface to use.
-   *
-   * By default this value is `null`
-   */
+  /// The network interface used for outgoing multicast packages.
+  ///
+  /// A value of `null` indicate that the system chooses the network
+  /// interface to use.
+  ///
+  /// By default this value is `null`
   @Deprecated("This property is not implemented. Use getRawOption and "
       "setRawOption instead.")
   NetworkInterface? multicastInterface;
 
-  /**
-   * Set or get, whether IPv4 broadcast is enabled.
-   *
-   * IPv4 broadcast needs to be enabled by the sender for sending IPv4
-   * broadcast packages. By default IPv4 broadcast is disabled.
-   *
-   * For IPv6 there is no general broadcast mechanism. Use multicast
-   * instead.
-   */
-  bool get broadcastEnabled;
-  void set broadcastEnabled(bool value);
+  /// Whether IPv4 broadcast is enabled.
+  ///
+  /// IPv4 broadcast needs to be enabled by the sender for sending IPv4
+  /// broadcast packages. By default IPv4 broadcast is disabled.
+  ///
+  /// For IPv6 there is no general broadcast mechanism. Use multicast
+  /// instead.
+  abstract bool broadcastEnabled;
 
-  /**
-   * Binds a socket to the given [host] and the [port].
-   *
-   * When the socket is bound and has started listening on [port], the returned
-   * future completes with the [RawDatagramSocket] of the bound socket.
-   *
-   * The [host] can either be a [String] or an [InternetAddress]. If [host] is a
-   * [String], [bind] will perform a [InternetAddress.lookup] and use the first
-   * value in the list. To listen on the loopback interface, which will allow
-   * only incoming connections from the local host, use the value
-   * [InternetAddress.loopbackIPv4] or [InternetAddress.loopbackIPv6].
-   * To allow for incoming connection from any network use either one of
-   * the values [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
-   * bind to all interfaces, or use the IP address of a specific interface.
-   *
-   * The [reuseAddress] should be set for all listeners that bind to the same
-   * address. Otherwise, it will fail with a [SocketException].
-   *
-   * The [reusePort] specifies whether the port can be reused.
-   *
-   * The [ttl] sets `time to live` of a datagram sent on the socket.
-   */
+  /// Binds a socket to the given [host] and [port].
+  ///
+  /// When the socket is bound and has started listening on [port], the returned
+  /// future completes with the [RawDatagramSocket] of the bound socket.
+  ///
+  /// The [host] can either be a [String] or an [InternetAddress]. If [host] is a
+  /// [String], [bind] will perform a [InternetAddress.lookup] and use the first
+  /// value in the list. To listen on the loopback interface, which will allow
+  /// only incoming connections from the local host, use the value
+  /// [InternetAddress.loopbackIPv4] or [InternetAddress.loopbackIPv6].
+  /// To allow for incoming connection from any network use either one of
+  /// the values [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+  /// bind to all interfaces, or use the IP address of a specific interface.
+  ///
+  /// The [reuseAddress] should be set for all listeners that bind to the same
+  /// address. Otherwise, it will fail with a [SocketException].
+  ///
+  /// The [reusePort] specifies whether the port can be reused.
+  ///
+  /// The [ttl] sets `time to live` of a datagram sent on the socket.
   external static Future<RawDatagramSocket> bind(host, int port,
       {bool reuseAddress = true, bool reusePort = false, int ttl = 1});
 
-  /**
-   * Returns the port used by this socket.
-   */
+  /// The port used by this socket.
   int get port;
 
-  /**
-   * Returns the address used by this socket.
-   */
+  /// The address used by this socket.
   InternetAddress get address;
 
-  /**
-   * Close the datagram socket.
-   */
+  /// Closes the datagram socket.
   void close();
 
-  /**
-   * Send a datagram.
-   *
-   * Returns the number of bytes written. This will always be either
-   * the size of [buffer] or `0`.
-   */
+  /// Sends a datagram.
+  ///
+  /// Returns the number of bytes written. This will always be either
+  /// the size of [buffer] or `0`.
   int send(List<int> buffer, InternetAddress address, int port);
 
-  /**
-   * Receive a datagram. If there are no datagrams available `null` is
-   * returned.
-   *
-   * The maximum length of the datagram that can be received is 65503 bytes.
-   */
+  /// Receives a datagram.
+  ///
+  /// Returns `null` if there are no datagrams available.
+  ///
+  /// The maximum length of the datagram that can be received is 65503 bytes.
   Datagram? receive();
 
-  /**
-   * Join a multicast group.
-   *
-   * If an error occur when trying to join the multicast group an
-   * exception is thrown.
-   */
+  /// Joins a multicast group.
+  ///
+  /// If an error occur when trying to join the multicast group, an
+  /// exception is thrown.
   void joinMulticast(InternetAddress group, [NetworkInterface? interface]);
 
-  /**
-   * Leave a multicast group.
-   *
-   * If an error occur when trying to join the multicase group an
-   * exception is thrown.
-   */
+  /// Leaves a multicast group.
+  ///
+  /// If an error occur when trying to join the multicase group, an
+  /// exception is thrown.
   void leaveMulticast(InternetAddress group, [NetworkInterface? interface]);
 
-  /**
-   * Use [getRawOption] to get low level information about the [RawSocket]. See
-   * [RawSocketOption] for available options.
-   *
-   * Returns [RawSocketOption.value] on success.
-   *
-   * Throws an [OSError] on failure.
-   */
+  /// Reads low level information about the [RawSocket].
+  ///
+  /// See [RawSocketOption] for available options.
+  ///
+  /// Returns [RawSocketOption.value] on success.
+  ///
+  /// Throws an [OSError] on failure.
   Uint8List getRawOption(RawSocketOption option);
 
-  /**
-   * Use [setRawOption] to customize the [RawSocket]. See [RawSocketOption] for
-   * available options.
-   *
-   * Throws an [OSError] on failure.
-   */
+  /// Customizes the [RawSocket].
+  ///
+  /// See [RawSocketOption] for available options.
+  ///
+  /// Throws an [OSError] on failure.
   void setRawOption(RawSocketOption option);
 }
 
diff --git a/sdk/lib/io/stdio.dart b/sdk/lib/io/stdio.dart
index 9fc8401..137b4e0 100644
--- a/sdk/lib/io/stdio.dart
+++ b/sdk/lib/io/stdio.dart
@@ -24,39 +24,37 @@
   }
 }
 
-/**
- * [Stdin] allows both synchronous and asynchronous reads from the standard
- * input stream.
- *
- * Mixing synchronous and asynchronous reads is undefined.
- */
+/// The standard input stream of the process.
+///
+/// Allows both synchronous and asynchronous reads from the standard
+/// input stream.
+///
+/// Mixing synchronous and asynchronous reads is undefined.
 class Stdin extends _StdStream implements Stream<List<int>> {
   int _fd;
 
   Stdin._(Stream<List<int>> stream, this._fd) : super(stream);
 
-  /**
-   * Read a line from stdin.
-   *
-   * Blocks until a full line is available.
-   *
-   * Lines my be terminated by either `<CR><LF>` or `<LF>`. On Windows in cases
-   * where the [stdioType] of stdin is [StdioType.terminal] the terminator may
-   * also be a single `<CR>`.
-   *
-   * Input bytes are converted to a string by [encoding].
-   * If [encoding] is omitted, it defaults to [systemEncoding].
-   *
-   * If [retainNewlines] is `false`, the returned String will not include the
-   * final line terminator. If `true`, the returned String will include the line
-   * terminator. Default is `false`.
-   *
-   * If end-of-file is reached after any bytes have been read from stdin,
-   * that data is returned without a line terminator.
-   * Returns `null` if no bytes preceded the end of input.
-   */
+  /// Reads a line from stdin.
+  ///
+  /// Blocks until a full line is available.
+  ///
+  /// Lines my be terminated by either `<CR><LF>` or `<LF>`. On Windows,
+  /// in cases where the [stdioType] of stdin is [StdioType.terminal],
+  /// the terminator may also be a single `<CR>`.
+  ///
+  /// Input bytes are converted to a string by [encoding].
+  /// If [encoding] is omitted, it defaults to [systemEncoding].
+  ///
+  /// If [retainNewlines] is `false`, the returned string will not include the
+  /// final line terminator. If `true`, the returned string will include the line
+  /// terminator. Default is `false`.
+  ///
+  /// If end-of-file is reached after any bytes have been read from stdin,
+  /// that data is returned without a line terminator.
+  /// Returns `null` if no bytes preceded the end of input.
   String? readLineSync(
-      {Encoding encoding: systemEncoding, bool retainNewlines: false}) {
+      {Encoding encoding = systemEncoding, bool retainNewlines = false}) {
     const CR = 13;
     const LF = 10;
     final List<int> line = <int>[];
@@ -112,74 +110,57 @@
     return encoding.decode(line);
   }
 
-  /**
-   * Check if echo mode is enabled on [stdin].
-   */
+  /// Whether echo mode is enabled on [stdin].
+  ///
+  /// If disabled, input from to console will not be echoed.
+  ///
+  /// Default depends on the parent process, but is usually enabled.
+  ///
+  /// On Windows this mode can only be enabled if [lineMode] is enabled as well.
   external bool get echoMode;
+  external set echoMode(bool echoMode);
 
-  /**
-   * Enable or disable echo mode on [stdin].
-   *
-   * If disabled, input from to console will not be echoed.
-   *
-   * Default depends on the parent process, but usually enabled.
-   *
-   * On Windows this mode can only be enabled if [lineMode] is enabled as well.
-   */
-  external void set echoMode(bool enabled);
-
-  /**
-   * Check if line mode is enabled on [stdin].
-   */
+  /// Whether line mode is enabled on [stdin].
+  ///
+  /// If enabled, characters are delayed until a newline character is entered.
+  /// If disabled, characters will be available as typed.
+  ///
+  /// Default depends on the parent process, but is usually enabled.
+  ///
+  /// On Windows this mode can only be disabled if [echoMode] is disabled as well.
   external bool get lineMode;
+  external set lineMode(bool lineMode);
 
-  /**
-   * Enable or disable line mode on [stdin].
-   *
-   * If enabled, characters are delayed until a new-line character is entered.
-   * If disabled, characters will be available as typed.
-   *
-   * Default depends on the parent process, but usually enabled.
-   *
-   * On Windows this mode can only be disabled if [echoMode] is disabled as well.
-   */
-  external void set lineMode(bool enabled);
-
-  /**
-    * Whether connected to a terminal that supports ANSI escape sequences.
-    *
-    * Not all terminals are recognized, and not all recognized terminals can
-    * report whether they support ANSI escape sequences, so this value is a
-    * best-effort attempt at detecting the support.
-    *
-    * The actual escape sequence support may differ between terminals,
-    * with some terminals supporting more escape sequences than others,
-    * and some terminals even differing in behavior for the same escape
-    * sequence.
-    *
-    * The ANSI color selection is generally supported.
-    *
-    * Currently, a `TERM` environment variable containing the string `xterm`
-    * will be taken as evidence that ANSI escape sequences are supported.
-    * On Windows, only versions of Windows 10 after v.1511
-    * ("TH2", OS build 10586) will be detected as supporting the output of
-    * ANSI escape sequences, and only versions after v.1607 ("Anniversary
-    * Update", OS build 14393) will be detected as supporting the input of
-    * ANSI escape sequences.
-    */
+  /// Whether connected to a terminal that supports ANSI escape sequences.
+  ///
+  /// Not all terminals are recognized, and not all recognized terminals can
+  /// report whether they support ANSI escape sequences, so this value is a
+  /// best-effort attempt at detecting the support.
+  ///
+  /// The actual escape sequence support may differ between terminals,
+  /// with some terminals supporting more escape sequences than others,
+  /// and some terminals even differing in behavior for the same escape
+  /// sequence.
+  ///
+  /// The ANSI color selection is generally supported.
+  ///
+  /// Currently, a `TERM` environment variable containing the string `xterm`
+  /// will be taken as evidence that ANSI escape sequences are supported.
+  /// On Windows, only versions of Windows 10 after v.1511
+  /// ("TH2", OS build 10586) will be detected as supporting the output of
+  /// ANSI escape sequences, and only versions after v.1607 ("Anniversary
+  /// Update", OS build 14393) will be detected as supporting the input of
+  /// ANSI escape sequences.
   external bool get supportsAnsiEscapes;
 
-  /**
-   * Synchronously read a byte from stdin. This call will block until a byte is
-   * available.
-   *
-   * If at end of file, -1 is returned.
-   */
+  /// Synchronously reads a byte from stdin.
+  ///
+  /// This call will block until a byte is available.
+  ///
+  /// If at end of file, -1 is returned.
   external int readByteSync();
 
-  /**
-   * Returns true if there is a terminal attached to stdin.
-   */
+  /// Whether there is a terminal attached to stdin.
   bool get hasTerminal {
     try {
       return stdioType(this) == StdioType.terminal;
@@ -192,73 +173,63 @@
   }
 }
 
-/**
- * [Stdout] represents the [IOSink] for either `stdout` or `stderr`.
- *
- * It provides a *blocking* `IOSink`, so using this to write will block until
- * the output is written.
- *
- * In some situations this blocking behavior is undesirable as it does not
- * provide the same non-blocking behavior as dart:io in general exposes.
- * Use the property [nonBlocking] to get an `IOSink` which has the non-blocking
- * behavior.
- *
- * This class can also be used to check whether `stdout` or `stderr` is
- * connected to a terminal and query some terminal properties.
- *
- * The [addError] API is inherited from  [StreamSink] and calling it will result
- * in an unhandled asynchronous error unless there is an error handler on
- * [done].
- */
+/// An [IOSink] connected to either the standard out or error of the process.
+///
+/// Provides a *blocking* `IOSink`, so using it to write will block until
+/// the output is written.
+///
+/// In some situations this blocking behavior is undesirable as it does not
+/// provide the same non-blocking behavior that `dart:io` in general exposes.
+/// Use the property [nonBlocking] to get an [IOSink] which has the non-blocking
+/// behavior.
+///
+/// This class can also be used to check whether `stdout` or `stderr` is
+/// connected to a terminal and query some terminal properties.
+///
+/// The [addError] API is inherited from [StreamSink] and calling it will result
+/// in an unhandled asynchronous error unless there is an error handler on
+/// [done].
 class Stdout extends _StdSink implements IOSink {
   final int _fd;
   IOSink? _nonBlocking;
 
   Stdout._(IOSink sink, this._fd) : super(sink);
 
-  /**
-   * Returns true if there is a terminal attached to stdout.
-   */
+  /// Whether there is a terminal attached to stdout.
   bool get hasTerminal => _hasTerminal(_fd);
 
-  /**
-   * Get the number of columns of the terminal.
-   *
-   * If no terminal is attached to stdout, a [StdoutException] is thrown. See
-   * [hasTerminal] for more info.
-   */
+  /// The number of columns of the terminal.
+  ///
+  /// If no terminal is attached to stdout, a [StdoutException] is thrown. See
+  /// [hasTerminal] for more info.
   int get terminalColumns => _terminalColumns(_fd);
 
-  /**
-   * Get the number of lines of the terminal.
-   *
-   * If no terminal is attached to stdout, a [StdoutException] is thrown. See
-   * [hasTerminal] for more info.
-   */
+  /// The number of lines of the terminal.
+  ///
+  /// If no terminal is attached to stdout, a [StdoutException] is thrown. See
+  /// [hasTerminal] for more info.
   int get terminalLines => _terminalLines(_fd);
 
-  /**
-    * Whether connected to a terminal that supports ANSI escape sequences.
-    *
-    * Not all terminals are recognized, and not all recognized terminals can
-    * report whether they support ANSI escape sequences, so this value is a
-    * best-effort attempt at detecting the support.
-    *
-    * The actual escape sequence support may differ between terminals,
-    * with some terminals supporting more escape sequences than others,
-    * and some terminals even differing in behavior for the same escape
-    * sequence.
-    *
-    * The ANSI color selection is generally supported.
-    *
-    * Currently, a `TERM` environment variable containing the string `xterm`
-    * will be taken as evidence that ANSI escape sequences are supported.
-    * On Windows, only versions of Windows 10 after v.1511
-    * ("TH2", OS build 10586) will be detected as supporting the output of
-    * ANSI escape sequences, and only versions after v.1607 ("Anniversary
-    * Update", OS build 14393) will be detected as supporting the input of
-    * ANSI escape sequences.
-    */
+  /// Whether connected to a terminal that supports ANSI escape sequences.
+  ///
+  /// Not all terminals are recognized, and not all recognized terminals can
+  /// report whether they support ANSI escape sequences, so this value is a
+  /// best-effort attempt at detecting the support.
+  ///
+  /// The actual escape sequence support may differ between terminals,
+  /// with some terminals supporting more escape sequences than others,
+  /// and some terminals even differing in behavior for the same escape
+  /// sequence.
+  ///
+  /// The ANSI color selection is generally supported.
+  ///
+  /// Currently, a `TERM` environment variable containing the string `xterm`
+  /// will be taken as evidence that ANSI escape sequences are supported.
+  /// On Windows, only versions of Windows 10 after v.1511
+  /// ("TH2", OS build 10586) will be detected as supporting the output of
+  /// ANSI escape sequences, and only versions after v.1607 ("Anniversary
+  /// Update", OS build 14393) will be detected as supporting the input of
+  /// ANSI escape sequences.
   bool get supportsAnsiEscapes => _supportsAnsiEscapes(_fd);
 
   external bool _hasTerminal(int fd);
@@ -266,16 +237,18 @@
   external int _terminalLines(int fd);
   external static bool _supportsAnsiEscapes(int fd);
 
-  /**
-   * Get a non-blocking `IOSink`.
-   */
+  /// A non-blocking `IOSink` for the same output.
   IOSink get nonBlocking {
     return _nonBlocking ??= new IOSink(new _FileStreamConsumer.fromStdio(_fd));
   }
 }
 
+/// Exception thrown by some operations of [Stdout]
 class StdoutException implements IOException {
+  /// Message describing cause of the exception.
   final String message;
+
+  /// The underlying OS error, if avaialble.
   final OSError? osError;
 
   const StdoutException(this.message, [this.osError]);
@@ -285,8 +258,12 @@
   }
 }
 
+/// Exception thrown by some operations of [Stdin]
 class StdinException implements IOException {
+  /// Message describing cause of the exception.
   final String message;
+
+  /// The underlying OS error, if avaialble.
   final OSError? osError;
 
   const StdinException(this.message, [this.osError]);
@@ -364,7 +341,7 @@
   Future get done => _sink.done;
 }
 
-/// The type of object a standard IO stream is attached to.
+/// The type of object a standard IO stream can be attached to.
 class StdioType {
   static const StdioType terminal = const StdioType._("terminal");
   static const StdioType pipe = const StdioType._("pipe");
@@ -425,7 +402,7 @@
   return _stderr ??= _StdIOUtils._getStdioOutputStream(_stderrFD);
 }
 
-/// For a stream, returns whether it is attached to a file, pipe, terminal, or
+/// Whether a stream is attached to a file, pipe, terminal, or
 /// something else.
 StdioType stdioType(object) {
   if (object is _StdStream) {
diff --git a/sdk/lib/io/string_transformer.dart b/sdk/lib/io/string_transformer.dart
index f31c41e..bf04327 100644
--- a/sdk/lib/io/string_transformer.dart
+++ b/sdk/lib/io/string_transformer.dart
@@ -56,9 +56,7 @@
     return encoded;
   }
 
-  /**
-   * Starts a chunked conversion.
-   */
+  /// Starts a chunked conversion.
   StringConversionSink startChunkedConversion(Sink<List<int>> sink) {
     return new _WindowsCodePageEncoderSink(sink);
   }
@@ -102,9 +100,7 @@
     return _decodeBytes(input);
   }
 
-  /**
-   * Starts a chunked conversion.
-   */
+  /// Starts a chunked conversion.
   ByteConversionSink startChunkedConversion(Sink<String> sink) {
     return new _WindowsCodePageDecoderSink(sink);
   }
diff --git a/sdk/lib/io/sync_socket.dart b/sdk/lib/io/sync_socket.dart
index 771edfd..e1e47e5 100644
--- a/sdk/lib/io/sync_socket.dart
+++ b/sdk/lib/io/sync_socket.dart
@@ -4,106 +4,83 @@
 
 part of dart.io;
 
-/**
- * A low-level class for communicating synchronously over a TCP socket.
- *
- * Warning: [RawSynchronousSocket] should probably only be used to connect to
- * 'localhost'. The operations below will block the calling thread to wait for
- * a response from the network. The thread can process no other events while
- * waiting for these operations to complete. [RawSynchronousSocket] is not
- * suitable for applications that require high performance or asynchronous I/O
- * such as a server. Instead such applications should use the non-blocking
- * sockets and asynchronous operations in the Socket or RawSocket classes.
- */
+/// A low-level class for communicating synchronously over a TCP socket.
+///
+/// Warning: [RawSynchronousSocket] should probably only be used to connect to
+/// 'localhost'. The operations below will block the calling thread to wait for
+/// a response from the network. The thread can process no other events while
+/// waiting for these operations to complete. [RawSynchronousSocket] is not
+/// suitable for applications that require high performance or asynchronous I/O
+/// such as a server. Instead such applications should use the non-blocking
+/// sockets and asynchronous operations in the [Socket] or [RawSocket] classes.
 abstract class RawSynchronousSocket {
-  /**
-   * Creates a new socket connection and returns a [RawSynchronousSocket].
-   *
-   * [host] can either be a [String] or an [InternetAddress]. If [host] is a
-   * [String], [connectSync] will perform a [InternetAddress.lookup] and try
-   * all returned [InternetAddress]es, until connected. Unless a
-   * connection was established, the error from the first failing connection is
-   * returned.
-   */
+  /// Creates a new socket connection and returns a [RawSynchronousSocket].
+  ///
+  /// The [host] can either be a [String] or an [InternetAddress].
+  /// If [host] is a [String], [connectSync] will perform a
+  /// [InternetAddress.lookup] and try all returned [InternetAddress]es,
+  /// until connected.
+  /// Unless a connection was established,
+  /// the error from the first failing connection is returned.
   external static RawSynchronousSocket connectSync(host, int port);
 
-  /**
-   * Returns the number of received and unread bytes in the socket that can be
-   * read.
-   */
+  /// The number of received and unread bytes in the socket that can be read.
   int available();
 
-  /**
-   * Closes the [RawSynchronousSocket].
-   *
-   * Once [closeSync] has been called, attempting to call [readSync],
-   * [readIntoSync], [writeFromSync], [remoteAddress], and [remotePort] will
-   * cause a [SocketException] to be thrown.
-   */
+  /// Closes the [RawSynchronousSocket].
+  ///
+  /// Once [closeSync] has been called, attempting to call [readSync],
+  /// [readIntoSync], [writeFromSync], [remoteAddress], and [remotePort] will
+  /// cause a [SocketException] to be thrown.
   void closeSync();
 
-  /**
-   * Reads into an existing [List<int>] from the socket into the range:
-   * [[start],[end]).
-   *
-   * Reads into an existing [List<int>] from the socket. If [start] is present,
-   * the bytes will be filled into [buffer] from index [start], otherwise index
-   * 0. If [end] is present, [end] - [start] bytes will be read into [buffer],
-   * otherwise up to [buffer.length]. If [end] == [start], no bytes are read.
-   * Returns the number of bytes read.
-   */
+  /// Reads bytes into an existing [buffer].
+  ///
+  /// Reads bytes and writes then into the the range of [buffer]
+  /// from [start] to [end].
+  /// The [start] must be non-negative and no greater than `buffer.length`.
+  /// If [end] is omitted, it defaults to [buffer.length].
+  /// Otherwise [end] must be no less than [start]
+  /// and no greater than `buffer.length`.
+  ///
+  /// Returns the number of bytes read. This maybe be less than `end - start`
+  /// if the file doesn't have that many bytes to read.
   int readIntoSync(List<int> buffer, [int start = 0, int? end]);
 
-  /**
-   * Reads up to [bytes] bytes from the socket.
-   *
-   * Blocks and waits for a response of up to a specified number of bytes
-   * sent by the socket. [bytes] specifies the maximum number of bytes to
-   * be read. Returns the list of bytes read, which could be less than the
-   * value specified by [bytes].
-   */
+  /// Reads up to [bytes] bytes from the socket.
+  ///
+  /// Blocks and waits for a response of up to a specified number of bytes
+  /// sent by the socket. [bytes] specifies the maximum number of bytes to
+  /// be read. Returns the list of bytes read, which could be less than the
+  /// value specified by [bytes].
   List<int>? readSync(int bytes);
 
-  /**
-   * Shutdown a socket in the provided direction.
-   *
-   * Calling shutdown will never throw an exception and calling it several times
-   * is supported. If both [SocketDirection.RECEIVE] and [SocketDirection.SEND]
-   * directions are closed, the socket is closed completely, the same as if
-   * [closeSync] has been called.
-   */
+  /// Shuts down a socket in the provided direction.
+  ///
+  /// Calling shutdown will never throw an exception and calling it several times
+  /// is supported. If both [SocketDirection.RECEIVE] and [SocketDirection.SEND]
+  /// directions are closed, the socket is closed completely, the same as if
+  /// [closeSync] has been called.
   void shutdown(SocketDirection direction);
 
-  /**
-   * Writes data from a specified range in a [List<int>] to the socket.
-   *
-   * Writes into the socket from a [List<int>]. If [start] is present, the bytes
-   * will be written to the socket starting from index [start]. If [start] is
-   * not present, the bytes will be written starting from index 0. If [end] is
-   * present, the [end] - [start] bytes will be written into the socket starting
-   * at index [start]. If [end] is not provided, [buffer.length] elements will
-   * be written to the socket starting from index [start]. If [end] == [start],
-   * nothing happens.
-   */
+  /// Writes from a [buffer] to the socket.
+  ///
+  /// Will read the buffer from index [start] to index [end].
+  /// The [start] must be non-negative and no greater than `buffer.length`.
+  /// If [end] is omitted, it defaults to [buffer.length].
+  /// Otherwise [end] must be no less than [start]
+  /// and no greater than `buffer.length`.
   void writeFromSync(List<int> buffer, [int start = 0, int? end]);
 
-  /**
-   * The port used by this socket.
-   */
+  /// The port used by this socket.
   int get port;
 
-  /**
-   * The remote port connected to by this socket.
-   */
+  /// The remote port connected to by this socket.
   int get remotePort;
 
-  /**
-   * The [InternetAddress] used to connect this socket.
-   */
+  /// The [InternetAddress] used to connect this socket.
   InternetAddress get address;
 
-  /**
-   * The remote [InternetAddress] connected to by this socket.
-   */
+  /// The remote [InternetAddress] connected to by this socket.
   InternetAddress get remoteAddress;
 }
diff --git a/tests/ffi/data_test.dart b/tests/ffi/data_test.dart
index 47b88c5..f2543d1 100644
--- a/tests/ffi/data_test.dart
+++ b/tests/ffi/data_test.dart
@@ -47,10 +47,8 @@
   testEquality();
   testAllocateVoid();
   testAllocateNativeFunction();
-  testSizeOfGeneric();
   testSizeOfVoid();
   testSizeOfNativeFunction();
-  testSizeOfNativeType();
   testDynamicInvocation();
   testMemoryAddressTruncation();
   testNullptrCast();
@@ -434,17 +432,6 @@
   });
 }
 
-void testSizeOfGeneric() {
-  int generic<T extends Pointer>() {
-    int size;
-    size = sizeOf<T>();
-    return size;
-  }
-
-  int size = generic<Pointer<Int64>>();
-  Expect.isTrue(size == 8 || size == 4);
-}
-
 void testSizeOfVoid() {
   Expect.throws(() {
     sizeOf<Void>();
@@ -457,12 +444,6 @@
   });
 }
 
-void testSizeOfNativeType() {
-  Expect.throws(() {
-    sizeOf();
-  });
-}
-
 void testDynamicInvocation() {
   dynamic p = calloc<Int8>();
   Expect.throws(() {
diff --git a/tests/ffi/vmspecific_static_checks_test.dart b/tests/ffi/vmspecific_static_checks_test.dart
index ff194bd..94a11e1 100644
--- a/tests/ffi/vmspecific_static_checks_test.dart
+++ b/tests/ffi/vmspecific_static_checks_test.dart
@@ -56,6 +56,11 @@
   testEmptyStructFromFunctionReturn();
   testAllocateGeneric();
   testAllocateNativeType();
+  testRefStruct();
+  testSizeOfGeneric();
+  testSizeOfNativeType();
+  testElementAtGeneric();
+  testElementAtNativeType();
 }
 
 typedef Int8UnOp = Int8 Function(Int8);
@@ -524,7 +529,9 @@
   external Pointer notEmpty;
 }
 
-class EmptyStruct extends Struct {}
+class EmptyStruct extends Struct {} //# 1099: ok
+
+class EmptyStruct extends Struct {} //# 1100: compile-time error
 
 void testEmptyStructLookupFunctionArgument() {
   testLibrary.lookupFunction< //# 1100: compile-time error
@@ -532,42 +539,54 @@
       void Function(EmptyStruct)>("DoesNotExist"); //# 1100: compile-time error
 }
 
+class EmptyStruct extends Struct {} //# 1101: compile-time error
+
 void testEmptyStructLookupFunctionReturn() {
   testLibrary.lookupFunction< //# 1101: compile-time error
       EmptyStruct Function(), //# 1101: compile-time error
       EmptyStruct Function()>("DoesNotExist"); //# 1101: compile-time error
 }
 
+class EmptyStruct extends Struct {} //# 1102: compile-time error
+
 void testEmptyStructAsFunctionArgument() {
-  final pointer =
-      Pointer<NativeFunction<Void Function(EmptyStruct)>>.fromAddress(1234);
+  final Pointer< //# 1102: compile-time error
+          NativeFunction< //# 1102: compile-time error
+              Void Function(EmptyStruct)>> //# 1102: compile-time error
+      pointer = Pointer.fromAddress(1234); //# 1102: compile-time error
   pointer.asFunction<void Function(EmptyStruct)>(); //# 1102: compile-time error
 }
 
+class EmptyStruct extends Struct {} //# 1103: compile-time error
+
 void testEmptyStructAsFunctionReturn() {
-  final pointer =
-      Pointer<NativeFunction<EmptyStruct Function()>>.fromAddress(1234);
+  final Pointer< //# 1103: compile-time error
+          NativeFunction<EmptyStruct Function()>> //# 1103: compile-time error
+      pointer = Pointer.fromAddress(1234); //# 1103: compile-time error
   pointer.asFunction<EmptyStruct Function()>(); //# 1103: compile-time error
 }
 
-void _consumeEmptyStruct(EmptyStruct e) {
-  print(e);
-}
+class EmptyStruct extends Struct {} //# 1104: compile-time error
+
+void _consumeEmptyStruct(EmptyStruct e) => //# 1104: compile-time error
+    print(e); //# 1104: compile-time error
 
 void testEmptyStructFromFunctionArgument() {
   Pointer.fromFunction<Void Function(EmptyStruct)>(//# 1104: compile-time error
       _consumeEmptyStruct); //# 1104: compile-time error
 }
 
-EmptyStruct _returnEmptyStruct() {
-  return EmptyStruct();
-}
+class EmptyStruct extends Struct {} //# 1105: compile-time error
+
+EmptyStruct _returnEmptyStruct() => EmptyStruct(); //# 1105: compile-time error
 
 void testEmptyStructFromFunctionReturn() {
   Pointer.fromFunction<EmptyStruct Function()>(//# 1105: compile-time error
       _returnEmptyStruct); //# 1105: compile-time error
 }
 
+class EmptyStruct extends Struct {} //# 1106: compile-time error
+
 class HasNestedEmptyStruct extends Struct {
   external EmptyStruct nestedEmptyStruct; //# 1106: compile-time error
 
@@ -587,3 +606,58 @@
 void testAllocateNativeType() {
   calloc(); //# 1321: compile-time error
 }
+
+void testRefStruct() {
+  final myStructPointer = calloc<TestStruct13>();
+  Pointer<Struct> structPointer = myStructPointer;
+  structPointer.ref; //# 1330: ok
+  calloc.free(myStructPointer);
+}
+
+T genericRef<T extends Struct>(Pointer<T> p) => //# 1200: ok
+    p.ref; //# 1200: ok
+
+T genericRef2<T extends Struct>(Pointer<T> p) => //# 1201: ok
+    p.cast<T>().ref; //# 1201: ok
+
+T genericRef3<T extends Struct>(Pointer<T> p) => //# 1202: ok
+    p[0]; //# 1202: ok
+
+void testSizeOfGeneric() {
+  int generic<T extends Pointer>() {
+    int size = sizeOf<IntPtr>();
+    size = sizeOf<T>(); //# 1300: ok
+    return size;
+  }
+
+  int size = generic<Pointer<Int64>>();
+}
+
+void testSizeOfNativeType() {
+  try {
+    sizeOf(); //# 1301: ok
+  } catch (e) {
+    print(e);
+  }
+}
+
+void testElementAtGeneric() {
+  Pointer<T> generic<T extends NativeType>(Pointer<T> pointer) {
+    Pointer<T> returnValue = pointer;
+    returnValue = returnValue.elementAt(1); //# 1310: ok
+    return returnValue;
+  }
+
+  Pointer<Int8> p = calloc();
+  p.elementAt(1);
+  generic(p);
+  calloc.free(p);
+}
+
+void testElementAtNativeType() {
+  Pointer<Int8> p = calloc();
+  p.elementAt(1);
+  Pointer<NativeType> p2 = p;
+  p2.elementAt(1); //# 1311: ok
+  calloc.free(p);
+}
diff --git a/tests/ffi_2/data_test.dart b/tests/ffi_2/data_test.dart
index 8fca1a1..59cc7f4 100644
--- a/tests/ffi_2/data_test.dart
+++ b/tests/ffi_2/data_test.dart
@@ -47,10 +47,8 @@
   testEquality();
   testAllocateVoid();
   testAllocateNativeFunction();
-  testSizeOfGeneric();
   testSizeOfVoid();
   testSizeOfNativeFunction();
-  testSizeOfNativeType();
   testDynamicInvocation();
   testMemoryAddressTruncation();
   testNullptrCast();
@@ -434,17 +432,6 @@
   });
 }
 
-void testSizeOfGeneric() {
-  int generic<T extends Pointer>() {
-    int size;
-    size = sizeOf<T>();
-    return size;
-  }
-
-  int size = generic<Pointer<Int64>>();
-  Expect.isTrue(size == 8 || size == 4);
-}
-
 void testSizeOfVoid() {
   Expect.throws(() {
     sizeOf<Void>();
@@ -457,12 +444,6 @@
   });
 }
 
-void testSizeOfNativeType() {
-  Expect.throws(() {
-    sizeOf();
-  });
-}
-
 void testDynamicInvocation() {
   dynamic p = calloc<Int8>();
   Expect.throws(() {
diff --git a/tests/ffi_2/vmspecific_static_checks_test.dart b/tests/ffi_2/vmspecific_static_checks_test.dart
index 8883658..369a8de 100644
--- a/tests/ffi_2/vmspecific_static_checks_test.dart
+++ b/tests/ffi_2/vmspecific_static_checks_test.dart
@@ -56,6 +56,11 @@
   testEmptyStructFromFunctionReturn();
   testAllocateGeneric();
   testAllocateNativeType();
+  testRefStruct();
+  testSizeOfGeneric();
+  testSizeOfNativeType();
+  testElementAtGeneric();
+  testElementAtNativeType();
 }
 
 typedef Int8UnOp = Int8 Function(Int8);
@@ -522,7 +527,9 @@
   Pointer notEmpty;
 }
 
-class EmptyStruct extends Struct {}
+class EmptyStruct extends Struct {} //# 1099: ok
+
+class EmptyStruct extends Struct {} //# 1100: compile-time error
 
 void testEmptyStructLookupFunctionArgument() {
   testLibrary.lookupFunction< //# 1100: compile-time error
@@ -530,42 +537,54 @@
       void Function(EmptyStruct)>("DoesNotExist"); //# 1100: compile-time error
 }
 
+class EmptyStruct extends Struct {} //# 1101: compile-time error
+
 void testEmptyStructLookupFunctionReturn() {
   testLibrary.lookupFunction< //# 1101: compile-time error
       EmptyStruct Function(), //# 1101: compile-time error
       EmptyStruct Function()>("DoesNotExist"); //# 1101: compile-time error
 }
 
+class EmptyStruct extends Struct {} //# 1102: compile-time error
+
 void testEmptyStructAsFunctionArgument() {
-  final pointer =
-      Pointer<NativeFunction<Void Function(EmptyStruct)>>.fromAddress(1234);
+  final Pointer< //# 1102: compile-time error
+          NativeFunction< //# 1102: compile-time error
+              Void Function(EmptyStruct)>> //# 1102: compile-time error
+      pointer = Pointer.fromAddress(1234); //# 1102: compile-time error
   pointer.asFunction<void Function(EmptyStruct)>(); //# 1102: compile-time error
 }
 
+class EmptyStruct extends Struct {} //# 1103: compile-time error
+
 void testEmptyStructAsFunctionReturn() {
-  final pointer =
-      Pointer<NativeFunction<EmptyStruct Function()>>.fromAddress(1234);
+  final Pointer< //# 1103: compile-time error
+          NativeFunction<EmptyStruct Function()>> //# 1103: compile-time error
+      pointer = Pointer.fromAddress(1234); //# 1103: compile-time error
   pointer.asFunction<EmptyStruct Function()>(); //# 1103: compile-time error
 }
 
-void _consumeEmptyStruct(EmptyStruct e) {
-  print(e);
-}
+class EmptyStruct extends Struct {} //# 1104: compile-time error
+
+void _consumeEmptyStruct(EmptyStruct e) => //# 1104: compile-time error
+    print(e); //# 1104: compile-time error
 
 void testEmptyStructFromFunctionArgument() {
   Pointer.fromFunction<Void Function(EmptyStruct)>(//# 1104: compile-time error
       _consumeEmptyStruct); //# 1104: compile-time error
 }
 
-EmptyStruct _returnEmptyStruct() {
-  return EmptyStruct();
-}
+class EmptyStruct extends Struct {} //# 1105: compile-time error
+
+EmptyStruct _returnEmptyStruct() => EmptyStruct(); //# 1105: compile-time error
 
 void testEmptyStructFromFunctionReturn() {
   Pointer.fromFunction<EmptyStruct Function()>(//# 1105: compile-time error
       _returnEmptyStruct); //# 1105: compile-time error
 }
 
+class EmptyStruct extends Struct {} //# 1106: compile-time error
+
 class HasNestedEmptyStruct extends Struct {
   EmptyStruct nestedEmptyStruct; //# 1106: compile-time error
 
@@ -585,3 +604,58 @@
 void testAllocateNativeType() {
   calloc(); //# 1321: compile-time error
 }
+
+void testRefStruct() {
+  final myStructPointer = calloc<TestStruct13>();
+  Pointer<Struct> structPointer = myStructPointer;
+  structPointer.ref; //# 1330: ok
+  calloc.free(myStructPointer);
+}
+
+T genericRef<T extends Struct>(Pointer<T> p) => //# 1200: ok
+    p.ref; //# 1200: ok
+
+T genericRef2<T extends Struct>(Pointer<T> p) => //# 1201: ok
+    p.cast<T>().ref; //# 1201: ok
+
+T genericRef3<T extends Struct>(Pointer<T> p) => //# 1202: ok
+    p[0]; //# 1202: ok
+
+void testSizeOfGeneric() {
+  int generic<T extends Pointer>() {
+    int size = sizeOf<IntPtr>();
+    size = sizeOf<T>(); //# 1300: ok
+    return size;
+  }
+
+  int size = generic<Pointer<Int64>>();
+}
+
+void testSizeOfNativeType() {
+  try {
+    sizeOf(); //# 1301: ok
+  } catch (e) {
+    print(e);
+  }
+}
+
+void testElementAtGeneric() {
+  Pointer<T> generic<T extends NativeType>(Pointer<T> pointer) {
+    Pointer<T> returnValue = pointer;
+    returnValue = returnValue.elementAt(1); //# 1310: ok
+    return returnValue;
+  }
+
+  Pointer<Int8> p = calloc();
+  p.elementAt(1);
+  generic(p);
+  calloc.free(p);
+}
+
+void testElementAtNativeType() {
+  Pointer<Int8> p = calloc();
+  p.elementAt(1);
+  Pointer<NativeType> p2 = p;
+  p2.elementAt(1); //# 1311: ok
+  calloc.free(p);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 0b12600..bb1be73 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 252
+PRERELEASE 253
 PRERELEASE_PATCH 0
\ No newline at end of file