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
+