Version 2.12.0-208.0.dev

Merge commit '8c2ab1d04f747d990fd9f97a29cc90e805bc086b' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 9b2a9f2..3e6b7cb 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -722,7 +722,7 @@
       "name": "vm_service",
       "rootUri": "../pkg/vm_service",
       "packageUri": "lib/",
-      "languageVersion": "2.6"
+      "languageVersion": "2.12"
     },
     {
       "name": "vm_snapshot_analysis",
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 2ef2bf1..d5be3ee 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -12,7 +12,7 @@
 ///
 /// Changing this value to `true` will cause some dead code warnings to appear
 /// for code that only exists to support the old behavior.
-const bool allowLocalBooleanVarsToPromoteByDefault = false;
+const bool allowLocalBooleanVarsToPromoteByDefault = true;
 
 /// [AssignedVariables] is a helper class capable of computing the set of
 /// variables that are potentially written to, and potentially captured by
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 896fd20..5e2ac34 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -5937,39 +5937,6 @@
     tip: r"""Try replacing them with normal or optional parameters.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<
-    Message Function(
-        String name,
-        String name2,
-        String
-            string3)> templateJsInteropNativeClassInAnnotation = const Template<
-        Message Function(String name, String name2, String string3)>(
-    messageTemplate:
-        r"""JS interop class '#name' conflicts with natively supported class '#name2' in '#string3'.""",
-    withArguments: _withArgumentsJsInteropNativeClassInAnnotation);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name, String name2, String string3)>
-    codeJsInteropNativeClassInAnnotation =
-    const Code<Message Function(String name, String name2, String string3)>(
-  "JsInteropNativeClassInAnnotation",
-);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsJsInteropNativeClassInAnnotation(
-    String name, String name2, String string3) {
-  if (name.isEmpty) throw 'No name provided';
-  name = demangleMixinApplicationName(name);
-  if (name2.isEmpty) throw 'No name provided';
-  name2 = demangleMixinApplicationName(name2);
-  if (string3.isEmpty) throw 'No string provided';
-  return new Message(codeJsInteropNativeClassInAnnotation,
-      message:
-          """JS interop class '${name}' conflicts with natively supported class '${name2}' in '${string3}'.""",
-      arguments: {'name': name, 'name2': name2, 'string3': string3});
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeJsInteropNonExternalConstructor =
     messageJsInteropNonExternalConstructor;
 
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index f8c1de7..9cb2e59 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -3868,194 +3868,6 @@
       });
     });
 
-    group('restrict', () {
-      test('reachability', () {
-        var h = Harness();
-        var reachable = FlowModel<Var, Type>(Reachability.initial);
-        var unreachable = reachable.setUnreachable();
-        expect(reachable.restrict(h, reachable, Set()), same(reachable));
-        expect(reachable.restrict(h, unreachable, Set()), same(unreachable));
-        expect(unreachable.restrict(h, reachable, Set()), same(unreachable));
-        expect(unreachable.restrict(h, unreachable, Set()), same(unreachable));
-      });
-
-      test('assignments', () {
-        var h = Harness();
-        var a = Var('a', 'int');
-        var b = Var('b', 'int');
-        var c = Var('c', 'int');
-        var d = Var('d', 'int');
-        var s0 = FlowModel<Var, Type>(Reachability.initial)
-            .declare(a, false)
-            .declare(b, false)
-            .declare(c, false)
-            .declare(d, false);
-        var s1 = s0
-            .write(a, Type('int'), new SsaNode<Var, Type>(null), h)
-            .write(b, Type('int'), new SsaNode<Var, Type>(null), h);
-        var s2 = s1
-            .write(a, Type('int'), new SsaNode<Var, Type>(null), h)
-            .write(c, Type('int'), new SsaNode<Var, Type>(null), h);
-        var result = s2.restrict(h, s1, Set());
-        expect(result.infoFor(a).assigned, true);
-        expect(result.infoFor(b).assigned, true);
-        expect(result.infoFor(c).assigned, true);
-        expect(result.infoFor(d).assigned, false);
-      });
-
-      test('write captured', () {
-        var h = Harness();
-        var a = Var('a', 'int');
-        var b = Var('b', 'int');
-        var c = Var('c', 'int');
-        var d = Var('d', 'int');
-        var s0 = FlowModel<Var, Type>(Reachability.initial)
-            .declare(a, false)
-            .declare(b, false)
-            .declare(c, false)
-            .declare(d, false);
-        // In s1, a and b are write captured.  In s2, a and c are.
-        var s1 = s0.conservativeJoin([a, b], [a, b]);
-        var s2 = s1.conservativeJoin([a, c], [a, c]);
-        var result = s2.restrict(h, s1, Set());
-        expect(
-          result.infoFor(a),
-          _matchVariableModel(writeCaptured: true, unassigned: false),
-        );
-        expect(
-          result.infoFor(b),
-          _matchVariableModel(writeCaptured: true, unassigned: false),
-        );
-        expect(
-          result.infoFor(c),
-          _matchVariableModel(writeCaptured: true, unassigned: false),
-        );
-        expect(
-          result.infoFor(d),
-          _matchVariableModel(writeCaptured: false, unassigned: true),
-        );
-      });
-
-      test('promotion', () {
-        void _check(String? thisType, String? otherType, bool unsafe,
-            List<String>? expectedChain) {
-          var h = Harness();
-          var x = Var('x', 'Object?');
-          var s0 = FlowModel<Var, Type>(Reachability.initial).declare(x, true);
-          var s1 = thisType == null
-              ? s0
-              : s0.tryPromoteForTypeCheck(h, x, Type(thisType)).ifTrue;
-          var s2 = otherType == null
-              ? s0
-              : s0.tryPromoteForTypeCheck(h, x, Type(otherType)).ifTrue;
-          var result = s1.restrict(h, s2, unsafe ? [x].toSet() : Set());
-          if (expectedChain == null) {
-            expect(result.variableInfo, contains(x));
-            expect(result.infoFor(x).promotedTypes, isNull);
-          } else {
-            expect(result.infoFor(x).promotedTypes!.map((t) => t.type).toList(),
-                expectedChain);
-          }
-        }
-
-        _check(null, null, false, null);
-        _check(null, null, true, null);
-        _check('int', null, false, ['int']);
-        _check('int', null, true, ['int']);
-        _check(null, 'int', false, ['int']);
-        _check(null, 'int', true, null);
-        _check('int?', 'int', false, ['int']);
-        _check('int', 'int?', false, ['int?', 'int']);
-        _check('int', 'String', false, ['String']);
-        _check('int?', 'int', true, ['int?']);
-        _check('int', 'int?', true, ['int']);
-        _check('int', 'String', true, ['int']);
-      });
-
-      test('promotion chains', () {
-        // Verify that the given promotion chain matches the expected list of
-        // strings.
-        void _checkChain(List<Type>? chain, List<String> expected) {
-          var strings = (chain ?? <Type>[]).map((t) => t.type).toList();
-          expect(strings, expected);
-        }
-
-        // Test the following scenario:
-        // - Prior to the try/finally block, the sequence of promotions in
-        //   [before] is done.
-        // - During the try block, the sequence of promotions in [inTry] is
-        //   done.
-        // - During the finally block, the sequence of promotions in
-        //   [inFinally] is done.
-        // - After calling `restrict` to refine the state from the finally
-        //   block, the expected promotion chain is [expectedResult].
-        void _check(List<String> before, List<String> inTry,
-            List<String> inFinally, List<String> expectedResult) {
-          var h = Harness();
-          var x = Var('x', 'Object?');
-          var initialModel =
-              FlowModel<Var, Type>(Reachability.initial).declare(x, true);
-          for (var t in before) {
-            initialModel =
-                initialModel.tryPromoteForTypeCheck(h, x, Type(t)).ifTrue;
-          }
-          _checkChain(initialModel.infoFor(x).promotedTypes, before);
-          var tryModel = initialModel;
-          for (var t in inTry) {
-            tryModel = tryModel.tryPromoteForTypeCheck(h, x, Type(t)).ifTrue;
-          }
-          var expectedTryChain = before.toList()..addAll(inTry);
-          _checkChain(tryModel.infoFor(x).promotedTypes, expectedTryChain);
-          var finallyModel = initialModel;
-          for (var t in inFinally) {
-            finallyModel =
-                finallyModel.tryPromoteForTypeCheck(h, x, Type(t)).ifTrue;
-          }
-          var expectedFinallyChain = before.toList()..addAll(inFinally);
-          _checkChain(
-              finallyModel.infoFor(x).promotedTypes, expectedFinallyChain);
-          var result = finallyModel.restrict(h, tryModel, {});
-          _checkChain(result.infoFor(x).promotedTypes, expectedResult);
-          // And verify that the inputs are unchanged.
-          _checkChain(initialModel.infoFor(x).promotedTypes, before);
-          _checkChain(tryModel.infoFor(x).promotedTypes, expectedTryChain);
-          _checkChain(
-              finallyModel.infoFor(x).promotedTypes, expectedFinallyChain);
-        }
-
-        _check(['Object'], ['Iterable', 'List'], ['num', 'int'],
-            ['Object', 'Iterable', 'List']);
-        _check([], ['Iterable', 'List'], ['num', 'int'], ['Iterable', 'List']);
-        _check(['Object'], ['Iterable', 'List'], [],
-            ['Object', 'Iterable', 'List']);
-        _check([], ['Iterable', 'List'], [], ['Iterable', 'List']);
-        _check(['Object'], [], ['num', 'int'], ['Object', 'num', 'int']);
-        _check([], [], ['num', 'int'], ['num', 'int']);
-        _check(['Object'], [], [], ['Object']);
-        _check([], [], [], []);
-        _check(
-            [], ['Object', 'Iterable'], ['num', 'int'], ['Object', 'Iterable']);
-        _check([], ['Object'], ['num', 'int'], ['Object', 'num', 'int']);
-        _check([], ['num', 'int'], ['Object', 'Iterable'], ['num', 'int']);
-        _check([], ['num', 'int'], ['Object'], ['num', 'int']);
-        _check([], ['Object', 'int'], ['num'], ['Object', 'int']);
-        _check([], ['Object', 'num'], ['int'], ['Object', 'num', 'int']);
-        _check([], ['num'], ['Object', 'int'], ['num', 'int']);
-        _check([], ['int'], ['Object', 'num'], ['int']);
-      });
-
-      test('variable present in one state but not the other', () {
-        var h = Harness();
-        var x = Var('x', 'Object?');
-        var s0 = FlowModel<Var, Type>(Reachability.initial);
-        var s1 = s0.declare(x, true);
-        expect(s0.restrict(h, s1, {}), same(s0));
-        expect(s0.restrict(h, s1, {x}), same(s0));
-        expect(s1.restrict(h, s0, {}), same(s0));
-        expect(s1.restrict(h, s0, {x}), same(s0));
-      });
-    });
-
     group('rebaseForward', () {
       test('reachability', () {
         var h = Harness();
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/local_boolean.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/local_boolean.dart
new file mode 100644
index 0000000..4c7b408
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/local_boolean.dart
@@ -0,0 +1,149 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+finalLocalBool(int? x) {
+  final bool b = x == null;
+  if (!b) {
+    /*nonNullable*/ x;
+  } else {
+    x;
+  }
+}
+
+localBool(int? x) {
+  bool b = x == null;
+  if (!b) {
+    /*nonNullable*/ x;
+  } else {
+    x;
+  }
+}
+
+localBool_assigned(int? x, bool b1) {
+  bool b2 = b1;
+  b2 = x == null;
+  if (!b2) {
+    /*nonNullable*/ x;
+  } else {
+    x;
+  }
+}
+
+localBool_assignedDynamic(int? x, bool b1) {
+  dynamic b2 = b1;
+  b2 = x == null;
+  if (!b2) {
+    /*nonNullable*/ x;
+  } else {
+    x;
+  }
+}
+
+parameter_assigned(int? x, bool b) {
+  b = x == null;
+  if (!b) {
+    /*nonNullable*/ x;
+  } else {
+    x;
+  }
+}
+
+parameter_assignedDynamic(int? x, dynamic b) {
+  b = x == null;
+  if (!b) {
+    /*nonNullable*/ x;
+  } else {
+    x;
+  }
+}
+
+lateFinalLocalBool(int? x) {
+  late final bool b = x == null;
+  if (!b) {
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    x;
+  } else {
+    x;
+  }
+}
+
+lateLocalBool(int? x) {
+  late bool b = x == null;
+  if (!b) {
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    x;
+  } else {
+    x;
+  }
+}
+
+lateLocalBool_assignedAndInitialized(int? x, bool b1) {
+  late bool b2 = b1;
+  b2 = x == null;
+  if (!b2) {
+    /*nonNullable*/ x;
+  } else {
+    x;
+  }
+}
+
+lateLocalBool_assignedButNotInitialized(int? x) {
+  late bool b;
+  b = x == null;
+  if (!b) {
+    /*nonNullable*/ x;
+  } else {
+    x;
+  }
+}
+
+rebaseWithDemotion(int? x, int? y, int? z, int? a) {
+  x;
+  y;
+  z;
+  if (y == null) return;
+  x;
+  /*nonNullable*/ y;
+  z;
+  bool b = x == null;
+  x;
+  /*nonNullable*/ y;
+  z;
+  if (z == null) return;
+  x;
+  /*nonNullable*/ y;
+  /*nonNullable*/ z;
+  y = a;
+  x;
+  y;
+  /*nonNullable*/ z;
+  if (b) return;
+  /*nonNullable*/ x;
+  y;
+  /*nonNullable*/ z;
+}
+
+compoundAssignment(int? x, dynamic b) {
+  b += x == null;
+  if (!b) {
+    // It's not safe to promote, because there's no guarantee that value of `b`
+    // has anything to do with the result of `x == null`.
+    x;
+  } else {
+    x;
+  }
+}
+
+ifNullAssignment(int? x, dynamic b) {
+  b ??= x == null;
+  if (!b) {
+    // It's not safe to promote, because there's no guarantee that value of `b`
+    // has anything to do with the result of `x == null`.
+    x;
+  } else {
+    x;
+  }
+}
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 91405e5..8bb8c6d 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -17,22 +17,17 @@
         messageJsInteropNonExternalConstructor,
         messageJsInteropNonExternalMember,
         templateJsInteropDartClassExtendsJSClass,
-        templateJsInteropJSClassExtendsDartClass,
-        templateJsInteropNativeClassInAnnotation;
+        templateJsInteropJSClassExtendsDartClass;
 
 import 'src/js_interop.dart';
 
 class JsInteropChecks extends RecursiveVisitor<void> {
   final CoreTypes _coreTypes;
   final DiagnosticReporter<Message, LocatedMessage> _diagnosticsReporter;
-  final Map<String, Class> _nativeClasses;
   bool _classHasJSAnnotation = false;
-  bool _classHasAnonymousAnnotation = false;
   bool _libraryHasJSAnnotation = false;
-  bool _libraryIsGlobalNamespace = false;
 
-  JsInteropChecks(
-      this._coreTypes, this._diagnosticsReporter, this._nativeClasses);
+  JsInteropChecks(this._coreTypes, this._diagnosticsReporter);
 
   @override
   void defaultMember(Member member) {
@@ -45,7 +40,6 @@
   @override
   void visitClass(Class cls) {
     _classHasJSAnnotation = hasJSInteropAnnotation(cls);
-    _classHasAnonymousAnnotation = hasAnonymousAnnotation(cls);
     var superclass = cls.superclass;
     if (superclass != null && superclass != _coreTypes.objectClass) {
       var superHasJSAnnotation = hasJSInteropAnnotation(superclass);
@@ -65,53 +59,14 @@
             cls.location.file);
       }
     }
-    if (_classHasJSAnnotation &&
-        !_classHasAnonymousAnnotation &&
-        _libraryIsGlobalNamespace) {
-      var jsClass = getJSName(cls);
-      if (jsClass.isEmpty) {
-        // No rename, take the name of the class directly.
-        jsClass = cls.name;
-      } else {
-        // Remove any global prefixes. Regex here is greedy and will only return
-        // a value for `className` that doesn't start with 'self.' or 'window.'.
-        var classRegexp = new RegExp(r'^((self|window)\.)*(?<className>.*)$');
-        var matches = classRegexp.allMatches(jsClass);
-        jsClass = matches.first.namedGroup('className');
-      }
-      if (_nativeClasses.containsKey(jsClass)) {
-        var nativeClass = _nativeClasses[jsClass];
-        _diagnosticsReporter.report(
-            templateJsInteropNativeClassInAnnotation.withArguments(
-                cls.name,
-                nativeClass.name,
-                nativeClass.enclosingLibrary.importUri.toString()),
-            cls.fileOffset,
-            cls.name.length,
-            cls.location.file);
-      }
-    }
     super.visitClass(cls);
-    _classHasAnonymousAnnotation = false;
     _classHasJSAnnotation = false;
   }
 
   @override
   void visitLibrary(Library lib) {
     _libraryHasJSAnnotation = hasJSInteropAnnotation(lib);
-    _libraryIsGlobalNamespace = false;
-    if (_libraryHasJSAnnotation) {
-      var libraryAnnotation = getJSName(lib);
-      var globalRegexp = new RegExp(r'^(self|window)(\.(self|window))*$');
-      if (libraryAnnotation.isEmpty ||
-          globalRegexp.hasMatch(libraryAnnotation)) {
-        _libraryIsGlobalNamespace = true;
-      }
-    } else {
-      _libraryIsGlobalNamespace = true;
-    }
     super.visitLibrary(lib);
-    _libraryIsGlobalNamespace = false;
     _libraryHasJSAnnotation = false;
   }
 
@@ -143,7 +98,7 @@
     }
 
     var isAnonymousFactory =
-        _classHasAnonymousAnnotation && procedure.isFactory;
+        isAnonymousClassMember(procedure) && procedure.isFactory;
 
     if (isAnonymousFactory) {
       if (procedure.function != null &&
diff --git a/pkg/_js_interop_checks/lib/src/js_interop.dart b/pkg/_js_interop_checks/lib/src/js_interop.dart
index 7831f2d..33ab00b 100644
--- a/pkg/_js_interop_checks/lib/src/js_interop.dart
+++ b/pkg/_js_interop_checks/lib/src/js_interop.dart
@@ -9,48 +9,15 @@
 bool hasJSInteropAnnotation(Annotatable a) =>
     a.annotations.any(_isPublicJSAnnotation);
 
-/// Returns true iff the node has an `@anonymous(...)` annotation from
-/// `package:js` or from the internal `dart:_js_annotations`.
-bool hasAnonymousAnnotation(Annotatable a) =>
-    a.annotations.any(_isAnonymousAnnotation);
-
-/// If [a] has a `@JS('...')` annotation, returns the value inside the
-/// parentheses.
-///
-/// If there is none or the class does not have a `@JS()` annotation, returns
-/// an empty String.
-String getJSName(Annotatable a) {
-  String jsClass = '';
-  for (var annotation in a.annotations) {
-    if (_isPublicJSAnnotation(annotation)) {
-      var jsClasses = _stringAnnotationValues(annotation);
-      if (jsClasses.length > 0) {
-        jsClass = jsClasses[0];
-      }
-    }
-  }
-  return jsClass;
-}
-
-/// If [a] has a `@Native('...')` annotation, returns the values inside the
-/// parentheses.
-///
-/// If there are none or the class does not have a `@Native()` annotation,
-/// returns an empty list. Unlike `@JS()`, the string within `@Native()` is
-/// allowed to contain several classes separated by a `,`.
-List<String> getNativeNames(Annotatable a) {
-  List<String> nativeClasses = [];
-  for (var annotation in a.annotations) {
-    if (_isNativeAnnotation(annotation)) {
-      nativeClasses.addAll(_stringAnnotationValues(annotation));
-    }
-  }
-  return nativeClasses;
+/// Returns true if [m] belongs to an anonymous class.
+bool isAnonymousClassMember(Member m) {
+  var enclosingClass = m.enclosingClass;
+  if (enclosingClass == null) return false;
+  return enclosingClass.annotations.any(_isAnonymousAnnotation);
 }
 
 final _packageJs = Uri.parse('package:js/js.dart');
 final _internalJs = Uri.parse('dart:_js_annotations');
-final _jsHelper = Uri.parse('dart:_js_helper');
 
 /// Returns true if [value] is the `JS` annotation from `package:js` or from
 /// `dart:_js_annotations`.
@@ -72,20 +39,12 @@
           c.enclosingLibrary.importUri == _internalJs);
 }
 
-bool _isNativeAnnotation(Expression value) {
-  var c = _annotationClass(value);
-  return c != null &&
-      c.name == 'Native' &&
-      c.enclosingLibrary.importUri == _jsHelper;
-}
-
 /// Returns the class of the instance referred to by metadata annotation [node].
 ///
 /// For example:
 ///
 /// - `@JS()` would return the "JS" class in "package:js".
 /// - `@anonymous` would return the "_Anonymous" class in "package:js".
-/// - `@Native` would return the "Native" class in "dart:_js_helper".
 ///
 /// This function works regardless of whether the CFE is evaluating constants,
 /// or whether the constant is a field reference (such as "anonymous" above).
@@ -101,40 +60,3 @@
   }
   return null;
 }
-
-/// Returns the string values inside of a metadata annotation [node].
-///
-/// For example:
-/// - `@JS('Foo')` would return ['Foo'].
-/// - `@Native('Foo,Bar')` would return ['Foo', 'Bar'].
-///
-/// [node] is expected to be an annotation with either StringConstants or
-/// StringLiterals that can be made up of multiple values. If there are none,
-/// this method returns an empty list. This method throws an assertion if there
-/// are multiple arguments or a named arg in the annotation.
-List<String> _stringAnnotationValues(Expression node) {
-  List<String> values = [];
-  if (node is ConstantExpression) {
-    var constant = node.constant;
-    if (constant is InstanceConstant) {
-      var argLength = constant.fieldValues.values.length;
-      if (argLength == 1) {
-        var value = constant.fieldValues.values.elementAt(0);
-        if (value is StringConstant) values.addAll(value.value.split(','));
-      } else if (argLength > 1) {
-        throw new ArgumentError('Method expects annotation with at most one '
-            'positional argument: $node.');
-      }
-    }
-  } else if (node is ConstructorInvocation) {
-    var argLength = node.arguments.positional.length;
-    if (argLength > 1 || node.arguments.named.length > 0) {
-      throw new ArgumentError('Method expects annotation with at most one '
-          'positional argument: $node.');
-    } else if (argLength == 1) {
-      var value = node.arguments.positional[0];
-      if (value is StringLiteral) values.addAll(value.value.split(','));
-    }
-  }
-  return values;
-}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
index 4c04dd2..c297b3c 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
@@ -43,6 +43,30 @@
       toType = target.staticParameterElement.type;
     } else if (parent is IndexExpression) {
       toType = parent.realTarget.staticType;
+    } else if (parent is ForEachPartsWithDeclaration) {
+      toType =
+          typeProvider.iterableType2(parent.loopVariable.declaredElement.type);
+    } else if (parent is ForEachPartsWithIdentifier) {
+      toType = typeProvider.iterableType2(parent.identifier.staticType);
+    } else if (parent is SpreadElement) {
+      var literal = parent.thisOrAncestorOfType<TypedLiteral>();
+      if (literal is ListLiteral) {
+        toType = literal.staticType.asInstanceOf(typeProvider.iterableElement);
+      } else if (literal is SetOrMapLiteral) {
+        toType = literal.staticType.isDartCoreSet
+            ? literal.staticType.asInstanceOf(typeProvider.iterableElement)
+            : literal.staticType.asInstanceOf(typeProvider.mapElement);
+      }
+    } else if (parent is YieldStatement) {
+      var enclosingExecutable =
+          parent.thisOrAncestorOfType<FunctionBody>().parent;
+      if (enclosingExecutable is FunctionDeclaration) {
+        toType = enclosingExecutable.returnType?.type;
+      } else if (enclosingExecutable is MethodDeclaration) {
+        toType = enclosingExecutable.returnType?.type;
+      } else if (enclosingExecutable is FunctionExpression) {
+        toType = enclosingExecutable.declaredElement.returnType;
+      }
     } else if ((parent is PrefixedIdentifier && target == parent.prefix) ||
         (parent is PropertyAccess && target == parent.target) ||
         (parent is MethodInvocation && target == parent.target) ||
@@ -54,7 +78,7 @@
     }
     if (toType != null &&
         !typeSystem.isAssignableTo(
-            toType, typeSystem.promoteToNonNull(fromType))) {
+            typeSystem.promoteToNonNull(fromType), toType)) {
       // The reason that `fromType` can't be assigned to `toType` is more than
       // just because it's nullable, in which case a null check won't fix the
       // problem.
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 832147a..7d7ee48 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -819,9 +819,33 @@
       CreateClass.newInstance,
       CreateMixin.newInstance,
     ],
+    CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE: [
+      AddNullCheck.newInstance,
+    ],
+    CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE: [
+      AddNullCheck.newInstance,
+    ],
+    CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE: [
+      AddNullCheck.newInstance,
+    ],
+    CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE: [
+      AddNullCheck.newInstance,
+    ],
     CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE: [
       AddNullCheck.newInstance,
     ],
+    CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION: [
+      AddNullCheck.newInstance,
+    ],
+    CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR: [
+      AddNullCheck.newInstance,
+    ],
+    CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD: [
+      AddNullCheck.newInstance,
+    ],
+    CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH: [
+      AddNullCheck.newInstance,
+    ],
     CompileTimeErrorCode.UNDEFINED_ANNOTATION: [
       ChangeTo.annotation,
       CreateClass.newInstance,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
index b445c7e..09750df 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -97,6 +99,55 @@
 ''');
   }
 
+  Future<void> test_forEachWithDeclarationCondition() async {
+    await resolveTestCode('''
+void f (List<String>? args) {
+  for (var e in args) print(e);
+}
+''');
+    await assertHasFix('''
+void f (List<String>? args) {
+  for (var e in args!) print(e);
+}
+''');
+  }
+
+  Future<void>
+      test_forEachWithDeclarationCondition_differByMoreThanNullability() async {
+    await resolveTestCode('''
+void f (List<int>? args) {
+  for (String e in args) print(e);
+}
+''');
+    await assertNoFix();
+  }
+
+  Future<void> test_forEachWithIdentifierCondition() async {
+    await resolveTestCode('''
+void f (List<String>? args) {
+  String s = "";
+  for (s in args) print(s);
+}
+''');
+    await assertHasFix('''
+void f (List<String>? args) {
+  String s = "";
+  for (s in args!) print(s);
+}
+''');
+  }
+
+  Future<void>
+      test_forEachWithIdentifierCondition_differByMoreThanNullability() async {
+    await resolveTestCode('''
+void f (List<int>? args) {
+  String s = "";
+  for (s in args) print(s);
+}
+''');
+    await assertNoFix();
+  }
+
   Future<void> test_functionExpressionInvocation() async {
     await resolveTestCode('''
 int f(C c) => c.func();
@@ -140,6 +191,21 @@
 ''');
   }
 
+  Future<void> test_initializer_assignable() async {
+    await resolveTestCode('''
+void f(int? x) {
+  num y = x;
+  print(y);
+}
+''');
+    await assertHasFix('''
+void f(int? x) {
+  num y = x!;
+  print(y);
+}
+''');
+  }
+
   Future<void> test_initializer_differByMoreThanNullability() async {
     await resolveTestCode('''
 void f(String x) {
@@ -176,4 +242,130 @@
 int f(String? s) => (s)!.length;
 ''');
   }
+
+  Future<void> test_spreadList() async {
+    await resolveTestCode('''
+void f (List<String>? args) {
+  [...args];
+}
+''');
+    await assertHasFix('''
+void f (List<String>? args) {
+  [...args!];
+}
+''');
+  }
+
+  Future<void> test_spreadList_differByMoreThanNullability() async {
+    await resolveTestCode('''
+void f (List<int>? args) {
+  <String>[...args];
+}
+''');
+    await assertNoFix(
+        errorFilter: (AnalysisError error) =>
+            error.errorCode !=
+            CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE);
+  }
+
+  Future<void> test_spreadMap() async {
+    await resolveTestCode('''
+void f (Map<int, String>? args) {
+  print({...args});
+}
+''');
+    await assertHasFix('''
+void f (Map<int, String>? args) {
+  print({...args!});
+}
+''');
+  }
+
+  Future<void> test_spreadSet() async {
+    await resolveTestCode('''
+void f (List<String>? args) {
+  print({...args});
+}
+''');
+    await assertHasFix('''
+void f (List<String>? args) {
+  print({...args!});
+}
+''');
+  }
+
+  Future<void> test_yieldEach_closure() async {
+    await resolveTestCode('''
+g(Iterable<String> Function() cb) {}
+f(List<String>? args) {
+  g(() sync* {
+    yield* args;
+  });
+}
+''');
+    await assertHasFix('''
+g(Iterable<String> Function() cb) {}
+f(List<String>? args) {
+  g(() sync* {
+    yield* args!;
+  });
+}
+''',
+        errorFilter: (AnalysisError error) =>
+            error.errorCode != CompileTimeErrorCode.YIELD_OF_INVALID_TYPE);
+  }
+
+  Future<void> test_yieldEach_localFunction() async {
+    await resolveTestCode('''
+g() {
+  Iterable<String> f(List<String>? args) sync* {
+    yield* args;
+  }
+}
+''');
+    await assertHasFix('''
+g() {
+  Iterable<String> f(List<String>? args) sync* {
+    yield* args!;
+  }
+}
+''',
+        errorFilter: (AnalysisError error) =>
+            error.errorCode ==
+            CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH);
+  }
+
+  Future<void> test_yieldEach_method() async {
+    await resolveTestCode('''
+class C {
+  Iterable<String> f(List<String>? args) sync* {
+    yield* args;
+  }
+}
+''');
+    await assertHasFix('''
+class C {
+  Iterable<String> f(List<String>? args) sync* {
+    yield* args!;
+  }
+}
+''',
+        errorFilter: (AnalysisError error) =>
+            error.errorCode != CompileTimeErrorCode.YIELD_OF_INVALID_TYPE);
+  }
+
+  Future<void> test_yieldEach_topLevel() async {
+    await resolveTestCode('''
+Iterable<String> f(List<String>? args) sync* {
+  yield* args;
+}
+''');
+    await assertHasFix('''
+Iterable<String> f(List<String>? args) sync* {
+  yield* args!;
+}
+''',
+        errorFilter: (AnalysisError error) =>
+            error.errorCode != CompileTimeErrorCode.YIELD_OF_INVALID_TYPE);
+  }
 }
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index ba3d969..6bfabd4 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -405,7 +405,15 @@
   CompileTimeErrorCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND,
   CompileTimeErrorCode.TYPE_TEST_WITH_NON_TYPE,
   CompileTimeErrorCode.TYPE_TEST_WITH_UNDEFINED_NAME,
+  CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE,
+  CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+  CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE,
+  CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
   CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE,
+  CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+  CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR,
+  CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD,
+  CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH,
   CompileTimeErrorCode.UNDEFINED_ANNOTATION,
   CompileTimeErrorCode.UNDEFINED_CLASS,
   CompileTimeErrorCode.UNDEFINED_CLASS_BOOLEAN,
diff --git a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
index 8946ab4..b4f7848 100644
--- a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/src/dart/element/type_schema.dart';
 import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:meta/meta.dart';
 
@@ -118,7 +119,9 @@
     iterable?.accept(_resolver);
     iterable = forEachParts.iterable;
 
-    _resolver.nullableDereferenceVerifier.expression(iterable);
+    _resolver.nullableDereferenceVerifier.expression(iterable,
+        errorCode:
+            CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR);
 
     loopVariable?.accept(_resolver);
     var elementType = _computeForEachElementType(iterable, isAsync);
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
index 9c98040..28cd2ec 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
@@ -43,7 +43,8 @@
       return;
     }
 
-    _nullableDereferenceVerifier.expression(function);
+    _nullableDereferenceVerifier.expression(function,
+        errorCode: CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE);
 
     var receiverType = function.staticType;
     if (receiverType is FunctionType) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index 3413ad8..a3349c3 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -466,7 +466,9 @@
         );
       } else {
         _setDynamicResolution(node);
-        _resolver.nullableDereferenceVerifier.report(receiver, receiverType);
+        _resolver.nullableDereferenceVerifier.report(receiver, receiverType,
+            errorCode: CompileTimeErrorCode
+                .UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE);
       }
       return;
     }
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
index dc990de..b12e424 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
@@ -12,6 +12,7 @@
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
 import 'package:analyzer/src/dart/resolver/resolution_result.dart';
+import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:meta/meta.dart';
 
@@ -91,10 +92,34 @@
         return _toResult();
       }
 
+      var parentExpression = (receiver ?? receiverErrorNode).parent;
+      CompileTimeErrorCode errorCode;
+      if (parentExpression == null) {
+        errorCode = CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE;
+      } else {
+        if (parentExpression is CascadeExpression) {
+          parentExpression =
+              (parentExpression as CascadeExpression).cascadeSections.first;
+        }
+        if (parentExpression is BinaryExpression) {
+          errorCode = CompileTimeErrorCode
+              .UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE;
+        } else if (parentExpression is MethodInvocation ||
+            parentExpression is MethodReferenceExpression) {
+          errorCode = CompileTimeErrorCode
+              .UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE;
+        } else if (parentExpression is FunctionExpressionInvocation) {
+          errorCode =
+              CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE;
+        } else {
+          errorCode =
+              CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE;
+        }
+      }
+
       _resolver.nullableDereferenceVerifier.report(
-        receiverErrorNode,
-        receiverType,
-      );
+          receiverErrorNode, receiverType,
+          errorCode: errorCode, arguments: [name]);
       _reportedGetterError = true;
       _reportedSetterError = true;
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
index e79edc9..672ed6f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
@@ -135,7 +135,9 @@
     node.expression.accept(_resolver);
 
     if (node.star != null) {
-      _resolver.nullableDereferenceVerifier.expression(node.expression);
+      _resolver.nullableDereferenceVerifier.expression(node.expression,
+          errorCode: CompileTimeErrorCode
+              .UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH);
     }
 
     _resolver.inferenceContext.bodyContext?.addYield(node);
diff --git a/pkg/analyzer/lib/src/error/bool_expression_verifier.dart b/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
index 05eb039..c5a7253 100644
--- a/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
+++ b/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
@@ -51,7 +51,9 @@
     if (!_checkForUseOfVoidResult(expression) &&
         !_typeSystem.isAssignableTo2(type, _boolType)) {
       if (type.element == _boolElement) {
-        _nullableDereferenceVerifier.report(expression, type);
+        _nullableDereferenceVerifier.report(expression, type,
+            errorCode: CompileTimeErrorCode
+                .UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION);
       } else {
         _errorReporter.reportErrorForNode(errorCode, expression, arguments);
       }
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 320b554..108a361 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -9738,6 +9738,44 @@
               "creating a type with the name '{0}'.",
           hasPublishedDocs: true);
 
+  static const CompileTimeErrorCode UNCHECKED_INVOCATION_OF_NULLABLE_VALUE =
+      CompileTimeErrorCode('UNCHECKED_USE_OF_NULLABLE_VALUE',
+          "The function can't be unconditionally invoked because it can be 'null'.",
+          correction: "Try adding a null check ('!').",
+          hasPublishedDocs: true,
+          uniqueName: 'UNCHECKED_INVOCATION_OF_NULLABLE_VALUE');
+
+  static const CompileTimeErrorCode
+      UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE = CompileTimeErrorCode(
+          'UNCHECKED_USE_OF_NULLABLE_VALUE',
+          "The method '{0}' can't be unconditionally invoked because the "
+              "receiver can be 'null'.",
+          correction:
+              "Try making the call conditional (using '?.') or adding a null "
+              "check to the target ('!').",
+          hasPublishedDocs: true,
+          uniqueName: 'UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE');
+
+  static const CompileTimeErrorCode
+      UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE = CompileTimeErrorCode(
+          'UNCHECKED_USE_OF_NULLABLE_VALUE',
+          "The operator '{0}' can't be unconditionally invoked because the "
+              "receiver can be 'null'.",
+          correction: "Try adding a null check to the target ('!').",
+          hasPublishedDocs: true,
+          uniqueName: 'UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE');
+
+  static const CompileTimeErrorCode
+      UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE = CompileTimeErrorCode(
+          'UNCHECKED_USE_OF_NULLABLE_VALUE',
+          "The property '{0}' can't be unconditionally accessed because the "
+              "receiver can be 'null'.",
+          correction:
+              "Try making the access conditional (using '?.') or adding a null "
+              "check to the target ('!').",
+          hasPublishedDocs: true,
+          uniqueName: 'UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE');
+
   /**
    * No parameters.
    */
@@ -9806,6 +9844,46 @@
               "it.",
           hasPublishedDocs: true);
 
+  static const CompileTimeErrorCode
+      UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION = CompileTimeErrorCode(
+          'UNCHECKED_USE_OF_NULLABLE_VALUE',
+          "A nullable expression can't be used as a condition.",
+          correction:
+              "Try checking that the value isn't 'null' before using it as a "
+              'condition.',
+          hasPublishedDocs: true,
+          uniqueName: 'UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION');
+
+  static const CompileTimeErrorCode
+      UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR = CompileTimeErrorCode(
+          'UNCHECKED_USE_OF_NULLABLE_VALUE',
+          "A nullable expression can't be used as an iterator in a for-in "
+              'loop.',
+          correction:
+              "Try checking that the value isn't 'null' before using it as an "
+              'iterator.',
+          hasPublishedDocs: true,
+          uniqueName: 'UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR');
+
+  static const CompileTimeErrorCode UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD =
+      CompileTimeErrorCode('UNCHECKED_USE_OF_NULLABLE_VALUE',
+          "A nullable expression can't be used in a spread.",
+          correction:
+              "Try checking that the value isn't 'null' before using it in a "
+              'spread, or use a null-aware spread.',
+          hasPublishedDocs: true,
+          uniqueName: 'UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD');
+
+  static const CompileTimeErrorCode
+      UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH = CompileTimeErrorCode(
+          'UNCHECKED_USE_OF_NULLABLE_VALUE',
+          "A nullable expression can't be used in a yield-each statement.",
+          correction:
+              "Try checking that the value isn't 'null' before using it in a "
+              'yield-each statement.',
+          hasPublishedDocs: true,
+          uniqueName: 'UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH');
+
   /**
    * No parameters.
    */
diff --git a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
index 26dae7d..1ed2687 100644
--- a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
+++ b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
@@ -21,33 +22,38 @@
   })  : _typeSystem = typeSystem,
         _errorReporter = errorReporter;
 
-  bool expression(Expression expression, {DartType type}) {
+  bool expression(Expression expression, {DartType type, ErrorCode errorCode}) {
     if (!_typeSystem.isNonNullableByDefault) {
       return false;
     }
 
     type ??= expression.staticType;
-    return _check(expression, type);
+    return _check(expression, type, errorCode: errorCode);
   }
 
-  void report(AstNode errorNode, DartType receiverType) {
-    var errorCode = receiverType == _typeSystem.typeProvider.nullType
-        ? CompileTimeErrorCode.INVALID_USE_OF_NULL_VALUE
-        : CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE;
-    _errorReporter.reportErrorForNode(errorCode, errorNode);
+  void report(AstNode errorNode, DartType receiverType,
+      {ErrorCode errorCode, List<String> arguments = const <String>[]}) {
+    if (receiverType == _typeSystem.typeProvider.nullType) {
+      errorCode = CompileTimeErrorCode.INVALID_USE_OF_NULL_VALUE;
+    } else {
+      errorCode ??= CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE;
+    }
+    _errorReporter.reportErrorForNode(errorCode, errorNode, arguments);
   }
 
   /// If the [receiverType] is potentially nullable, report it.
   ///
   /// The [errorNode] is usually the receiver of the invocation, but if the
   /// receiver is the implicit `this`, the name of the invocation.
-  bool _check(AstNode errorNode, DartType receiverType) {
+  ///
+  /// Returns whether [receiverType] was reported.
+  bool _check(AstNode errorNode, DartType receiverType, {ErrorCode errorCode}) {
     if (identical(receiverType, DynamicTypeImpl.instance) ||
         !_typeSystem.isPotentiallyNullable(receiverType)) {
       return false;
     }
 
-    report(errorNode, receiverType);
+    report(errorNode, receiverType, errorCode: errorCode);
     return true;
   }
 }
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index fed64ed..4ffeb7e 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1868,7 +1868,9 @@
     super.visitSpreadElement(node);
 
     if (!node.isNullAware) {
-      nullableDereferenceVerifier.expression(node.expression);
+      nullableDereferenceVerifier.expression(node.expression,
+          errorCode:
+              CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD);
     }
   }
 
diff --git a/pkg/analyzer/test/id_tests/nullability_test.dart b/pkg/analyzer/test/id_tests/nullability_test.dart
index 1490e2e..19c6869 100644
--- a/pkg/analyzer/test/id_tests/nullability_test.dart
+++ b/pkg/analyzer/test/id_tests/nullability_test.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/null_safety_understanding_flag.dart';
+import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/analysis/testing_data.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -78,9 +79,9 @@
         !node.inDeclarationContext()) {
       var element = node.staticElement;
       if (element is LocalVariableElement || element is ParameterElement) {
-        TypeImpl promotedType = node.staticType;
+        TypeImpl promotedType = _readType(node);
         TypeImpl declaredType = (element as VariableElement).type;
-        var isPromoted = promotedType != declaredType;
+        var isPromoted = promotedType != null && promotedType != declaredType;
         if (isPromoted &&
             _typeSystem.isPotentiallyNullable(declaredType) &&
             !_typeSystem.isPotentiallyNullable(promotedType)) {
@@ -90,6 +91,19 @@
     }
     return null;
   }
+
+  static DartType _readType(SimpleIdentifier node) {
+    var parent = node.parent;
+    if (parent is AssignmentExpression && parent.leftHandSide == node) {
+      return parent.readType;
+    } else if (parent is PostfixExpression) {
+      return parent.readType;
+    } else if (parent is PrefixExpression) {
+      return parent.readType;
+    } else {
+      return node.staticType;
+    }
+  }
 }
 
 class _NullabilityDataInterpreter implements DataInterpreter<String> {
diff --git a/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
index a1bfdde..8e76124 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
@@ -164,7 +164,7 @@
   x<int>(1 + 2);
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+      error(CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 21, 1),
     ]);
 
     assertFunctionExpressionInvocation(
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index 9750759..7ed306d 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -1099,7 +1099,8 @@
 }
 ''', [
       if (typeToStringWithNullability)
-        error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 61, 5),
+        error(
+            CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 61, 5),
       error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 61, 5),
     ]);
 
@@ -1122,7 +1123,8 @@
 }
 ''', [
       if (typeToStringWithNullability)
-        error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 23, 3),
+        error(
+            CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 23, 3),
       error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 23, 3),
     ]);
 
@@ -1145,7 +1147,8 @@
 }
 ''', [
       if (typeToStringWithNullability)
-        error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 26, 5),
+        error(
+            CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 26, 5),
       error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 26, 3),
     ]);
     assertMethodInvocation(
@@ -1164,7 +1167,8 @@
 }
 ''', [
       if (typeToStringWithNullability)
-        error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 22, 3),
+        error(
+            CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 22, 3),
       error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 22, 3),
     ]);
 
@@ -2466,7 +2470,8 @@
   foo.call();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 26, 3),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          26, 3),
     ]);
 
     assertMethodInvocation2(
@@ -2517,7 +2522,8 @@
   a.foo();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 46, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          46, 1),
     ]);
 
     assertMethodInvocation2(
@@ -2543,7 +2549,8 @@
   a.foo();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 84, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          84, 1),
     ]);
 
     assertMethodInvocation2(
@@ -2610,7 +2617,8 @@
   a.foo();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 29, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          29, 1),
     ]);
 
     assertMethodInvocation2(
@@ -2634,7 +2642,8 @@
   a.foo();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 67, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          67, 1),
     ]);
 
     assertMethodInvocation2(
diff --git a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
index 33a2b3c..b263cdf 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
@@ -648,7 +648,8 @@
   !a?.foo;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 55, 6),
+      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+          55, 6),
     ]);
 
     assertPrefixExpression(
@@ -672,7 +673,8 @@
   -a?.foo;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 51, 6),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          51, 6),
     ]);
 
     assertPrefixExpression(
@@ -746,7 +748,8 @@
   ~a?.foo;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 51, 6),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          51, 6),
     ]);
 
     assertPrefixExpression(
diff --git a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
index c6e60f7..63ab662 100644
--- a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
@@ -520,7 +520,8 @@
 ''');
     assertErrorsInResult(expectedErrorsByNullability(
       nullable: [
-        error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 33, 3),
+        error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+            33, 3),
       ],
       legacy: [
         error(CompileTimeErrorCode.UNDEFINED_GETTER, 37, 3),
diff --git a/pkg/analyzer/test/src/diagnostics/null_safety_read_write_test.dart b/pkg/analyzer/test/src/diagnostics/null_safety_read_write_test.dart
index 8729624..2920519 100644
--- a/pkg/analyzer/test/src/diagnostics/null_safety_read_write_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/null_safety_read_write_test.dart
@@ -515,7 +515,8 @@
 ''', [
       error(CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE, 68,
           1),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 68, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          68, 1),
     ]);
     _assertAssigned('x +=', assigned: false, unassigned: true);
   }
@@ -530,7 +531,8 @@
 ''', [
       error(CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE, 68,
           1),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 68, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          68, 1),
     ]);
     _assertAssigned('x++', assigned: false, unassigned: true);
   }
@@ -545,7 +547,8 @@
 ''', [
       error(CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE, 70,
           1),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 70, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          70, 1),
     ]);
     _assertAssigned('x; // 0', assigned: false, unassigned: true);
   }
@@ -581,7 +584,8 @@
   x += 1;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 90, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          90, 1),
     ]);
     _assertAssigned('x +=', assigned: false, unassigned: false);
   }
@@ -595,7 +599,8 @@
   x++;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 90, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          90, 1),
     ]);
     _assertAssigned('x++', assigned: false, unassigned: false);
   }
@@ -609,7 +614,8 @@
   ++x; // 0
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 92, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          92, 1),
     ]);
     _assertAssigned('x; // 0', assigned: false, unassigned: false);
   }
diff --git a/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
index 00ed468..1bb51ac 100644
--- a/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
@@ -77,7 +77,10 @@
   x + (1 + 2);
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+      error(
+          CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE,
+          21,
+          1),
     ]);
 
     assertBinaryExpression(
@@ -121,7 +124,7 @@
   x();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+      error(CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 21, 1),
     ]);
   }
 
@@ -201,7 +204,8 @@
   x[0];
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          21, 1),
     ]);
 
     assertIndexExpression(
@@ -218,7 +222,8 @@
   x[0] += 1 + 2;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          21, 1),
     ]);
 
     assertAssignment(
@@ -249,7 +254,8 @@
   x[0] = 1 + 2;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          21, 1),
     ]);
 
     assertIndexExpression(
@@ -358,7 +364,8 @@
   x++;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          21, 1),
     ]);
 
     assertPostfixExpression(
@@ -399,7 +406,8 @@
   ++x;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 23, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          23, 1),
     ]);
 
     assertPrefixExpression(
@@ -509,7 +517,8 @@
   x.foo;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          21, 1),
     ]);
 
     assertSimpleIdentifier(
diff --git a/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart b/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart
index 5c1a04d..5e0338c 100644
--- a/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart
@@ -161,8 +161,10 @@
   }
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 126, 4),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 154, 4),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          126, 4),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          154, 4),
     ]);
   }
 
@@ -202,8 +204,10 @@
   }
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 68, 3),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 79, 4),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          68, 3),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          79, 4),
     ]);
   }
 
@@ -233,7 +237,8 @@
   }
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 78, 4),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          78, 4),
     ]);
   }
 
@@ -277,8 +282,10 @@
   }
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 93, 3),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 102, 4),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          93, 3),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          102, 4),
     ]);
   }
 
@@ -322,8 +329,10 @@
   }
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 93, 3),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 106, 4),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          93, 3),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          106, 4),
     ]);
   }
 }
@@ -347,7 +356,8 @@
   if(x && true) {}
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 22, 1),
+      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+          22, 1),
     ]);
   }
 
@@ -376,7 +386,8 @@
   assert(x);
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 26, 1),
+      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+          26, 1),
     ]);
   }
 
@@ -397,7 +408,8 @@
   b.a.x = 2;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 100, 3),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          100, 3),
     ]);
 
     assertAssignment(
@@ -482,7 +494,8 @@
   b.a.y += 0;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 109, 5),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          109, 5),
     ]);
 
     assertAssignment(
@@ -536,7 +549,8 @@
   b.a.x += 2;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 3),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          101, 3),
     ]);
 
     assertAssignment(
@@ -580,7 +594,8 @@
   y += 0;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 31, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          31, 1),
     ]);
     var assignment1 = findNode.assignment('x +=');
     var assignment2 = findNode.assignment('y +=');
@@ -651,7 +666,8 @@
   x..[0] = 1;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 24, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          24, 1),
     ]);
   }
 
@@ -671,7 +687,8 @@
   x..abs();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          18, 1),
     ]);
   }
 
@@ -691,7 +708,8 @@
   x..isEven;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          18, 1),
     ]);
   }
 
@@ -732,7 +750,8 @@
 }
 ''', [
       error(HintCode.UNUSED_LOCAL_VARIABLE, 28, 1),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 33, 1),
+      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR,
+          33, 1),
     ]);
   }
 
@@ -746,7 +765,8 @@
   x.foo;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 58, 1),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          58, 1),
     ]);
   }
 
@@ -766,7 +786,8 @@
   if (x) {}
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 23, 1),
+      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+          23, 1),
     ]);
   }
 
@@ -786,7 +807,8 @@
   x[0];
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 19, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          19, 1),
     ]);
   }
 
@@ -806,7 +828,7 @@
   x();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 23, 1),
+      error(CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 23, 1),
     ]);
   }
 
@@ -826,7 +848,7 @@
   x();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 25, 1),
+      error(CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 25, 1),
     ]);
   }
 
@@ -882,7 +904,8 @@
   x.isEven;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          18, 1),
     ]);
     assertSimpleIdentifier(
       findNode.simple('isEven'),
@@ -907,7 +930,8 @@
   (x).isEven;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 3),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          18, 3),
     ]);
   }
 
@@ -926,7 +950,8 @@
   x.isEven;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 27, 1),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          27, 1),
     ]);
   }
 
@@ -936,7 +961,7 @@
   x.first();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 38, 7),
+      error(CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 38, 7),
     ]);
   }
 
@@ -982,7 +1007,8 @@
   x.round();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          18, 1),
     ]);
   }
 
@@ -996,7 +1022,8 @@
   x.foo();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 54, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          54, 1),
     ]);
   }
 
@@ -1031,7 +1058,8 @@
   x.call();
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 19, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          19, 1),
     ]);
   }
 
@@ -1054,17 +1082,20 @@
 }
 ''', [
       error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          18, 1),
     ]);
   }
 
   test_not_nonNullable() async {
-    await assertNoErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m() {
   bool x = true;
   if(!x) {}
 }
-''');
+''', [
+      error(HintCode.DEAD_CODE, 32, 2),
+    ]);
   }
 
   test_not_nullable() async {
@@ -1074,7 +1105,8 @@
   if(!x) {}
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 23, 1),
+      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+          23, 1),
     ]);
   }
 
@@ -1131,7 +1163,10 @@
   x - 3;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+      error(
+          CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE,
+          18,
+          1),
     ]);
   }
 
@@ -1151,7 +1186,10 @@
   x + 3;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+      error(
+          CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE,
+          18,
+          1),
     ]);
   }
 
@@ -1174,7 +1212,8 @@
 }
 ''', [
       error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          18, 1),
     ]);
   }
 
@@ -1192,7 +1231,8 @@
   x++;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 14, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          14, 1),
     ]);
   }
 
@@ -1208,7 +1248,8 @@
   x++;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 77, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          77, 1),
     ]);
   }
 
@@ -1231,7 +1272,8 @@
 }
 ''', [
       error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 20, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          20, 1),
     ]);
   }
 
@@ -1249,7 +1291,8 @@
   ++x;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 16, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          16, 1),
     ]);
   }
 
@@ -1272,7 +1315,8 @@
 }
 ''', [
       error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 19, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          19, 1),
     ]);
   }
 
@@ -1288,17 +1332,20 @@
   -x;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 73, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          73, 1),
     ]);
   }
 
   test_or_nonNullable() async {
-    await assertNoErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 m() {
   bool x = true;
   if(x || false) {}
 }
-''');
+''', [
+      error(HintCode.DEAD_CODE, 33, 5),
+    ]);
   }
 
   test_or_nullable() async {
@@ -1308,7 +1355,8 @@
   if(x || false) {}
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 22, 1),
+      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+          22, 1),
     ]);
   }
 
@@ -1326,7 +1374,8 @@
   x += 1;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 14, 1),
+      error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+          14, 1),
     ]);
   }
 
@@ -1342,7 +1391,8 @@
   a.x; // 2
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 66, 1),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          66, 1),
     ]);
     var propertyAccess1 = findNode.propertyAccess('a?.x; // 1');
     var propertyAccess2 = findNode.prefixed('a.x; // 2');
@@ -1373,7 +1423,8 @@
   b.a.x; // 2
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 3),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          101, 3),
     ]);
     var propertyAccess1 = findNode.propertyAccess('b.a?.x; // 1');
     var propertyAccess2 = findNode.propertyAccess('b.a.x; // 2');
@@ -1404,7 +1455,8 @@
   b.a.x; // 2
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 1),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          101, 1),
     ]);
     var propertyAccess1 = findNode.propertyAccess('x; // 1');
     var propertyAccess2 = findNode.propertyAccess('x; // 2');
@@ -1440,7 +1492,8 @@
   c.b.a.x; // 2
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 142, 5),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          142, 5),
     ]);
     var propertyAccess1 = findNode.propertyAccess('x; // 1');
     var propertyAccess2 = findNode.propertyAccess('x; // 2');
@@ -1476,7 +1529,8 @@
   c.b.a.x; // 2
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 148, 3),
+      error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+          148, 3),
     ]);
     var propertyAccess1 = findNode.propertyAccess('x; // 1');
     var propertyAccess2 = findNode.propertyAccess('x; // 2');
@@ -1510,7 +1564,8 @@
   [...list];
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 26, 4),
+      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD, 26,
+          4),
     ]);
   }
 
@@ -1530,7 +1585,8 @@
   x ? 0 : 1;
 }
 ''', [
-      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 19, 1),
+      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+          19, 1),
     ]);
   }
 
@@ -1551,4 +1607,26 @@
 }
 ''');
   }
+
+  test_yieldEach_nonNullable() async {
+    await assertNoErrorsInCode(r'''
+m() sync* {
+  List<int> x = [];
+  yield* x;
+}
+''');
+  }
+
+  test_yieldEach_nullable() async {
+    await assertErrorsInCode(r'''
+m() sync* {
+  List<int>? x;
+  yield* x;
+}
+''', [
+      error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 37, 1),
+      error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH,
+          37, 1),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 3dd7497..d395869 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -8408,9 +8408,28 @@
 
 ### unchecked_use_of_nullable_value
 
+_A nullable expression can't be used as a condition._
+
+_A nullable expression can't be used as an iterator in a for-in loop._
+
+_A nullable expression can't be used in a spread._
+
+_A nullable expression can't be used in a yield-each statement._
+
 _An expression whose value can be 'null' must be null-checked before it can be
 dereferenced._
 
+_The function can't be unconditionally invoked because it can be 'null'._
+
+_The method '{0}' can't be unconditionally invoked because the receiver can be
+'null'._
+
+_The operator '{0}' can't be unconditionally invoked because the receiver can be
+'null'._
+
+_The property '{0}' can't be unconditionally accessed because the receiver can
+be 'null'._
+
 #### Description
 
 The analyzer produces this diagnostic when an expression whose type is
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index 7af0873..49923c1 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -9,7 +9,6 @@
 import 'package:_fe_analyzer_shared/src/messages/codes.dart'
     show Message, LocatedMessage;
 import 'package:_js_interop_checks/js_interop_checks.dart';
-import 'package:_js_interop_checks/src/js_interop.dart';
 import 'package:kernel/ast.dart' as ir;
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
@@ -125,20 +124,9 @@
       ReferenceFromIndex referenceFromIndex,
       {void logger(String msg),
       ChangedStructureNotifier changedStructureNotifier}) {
-    var nativeClasses = <String, ir.Class>{};
-    for (var library in component.libraries) {
-      for (var cls in library.classes) {
-        var nativeNames = getNativeNames(cls);
-        for (var nativeName in nativeNames) {
-          nativeClasses[nativeName] = cls;
-        }
-      }
-    }
     for (var library in libraries) {
-      JsInteropChecks(
-              coreTypes,
-              diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>,
-              nativeClasses)
+      JsInteropChecks(coreTypes,
+              diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>)
           .visitLibrary(library);
     }
     lowering.transformLibraries(
diff --git a/pkg/dds/lib/vm_service_extensions.dart b/pkg/dds/lib/vm_service_extensions.dart
index 5b540da..8373b87 100644
--- a/pkg/dds/lib/vm_service_extensions.dart
+++ b/pkg/dds/lib/vm_service_extensions.dart
@@ -145,10 +145,12 @@
             )
             .toList()
             .cast<Event>() {
-    type = json['type'];
     this.json = json;
   }
 
+  @override
+  String get type => 'StreamHistory';
+
   /// Historical [Event]s for a stream.
   List<Event> get history => UnmodifiableListView(_history);
   final List<Event> _history;
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index 9f3e929..ca82d2e 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -17,7 +17,6 @@
 import 'package:kernel/target/targets.dart';
 import 'package:kernel/transformations/track_widget_constructor_locations.dart';
 import 'package:_js_interop_checks/js_interop_checks.dart';
-import 'package:_js_interop_checks/src/js_interop.dart';
 
 import 'constants.dart' show DevCompilerConstantsBackend;
 import 'kernel_helpers.dart';
@@ -153,21 +152,10 @@
       ReferenceFromIndex referenceFromIndex,
       {void Function(String msg) logger,
       ChangedStructureNotifier changedStructureNotifier}) {
-    var nativeClasses = <String, Class>{};
-    for (var library in component.libraries) {
-      for (var cls in library.classes) {
-        var nativeNames = getNativeNames(cls);
-        for (var nativeName in nativeNames) {
-          nativeClasses[nativeName] = cls;
-        }
-      }
-    }
     for (var library in libraries) {
       _CovarianceTransformer(library).transform();
-      JsInteropChecks(
-              coreTypes,
-              diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>,
-              nativeClasses)
+      JsInteropChecks(coreTypes,
+              diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>)
           .visitLibrary(library);
     }
   }
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index afaa87e..c275e1e 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -488,8 +488,6 @@
 JsInteropJSClassExtendsDartClass/example: Fail # Web compiler specific
 JsInteropNamedParameters/analyzerCode: Fail # Web compiler specific
 JsInteropNamedParameters/example: Fail # Web compiler specific
-JsInteropNativeClassInAnnotation/analyzerCode: Fail # Web compiler specific
-JsInteropNativeClassInAnnotation/example: Fail # Web compiler specific
 JsInteropNonExternalConstructor/analyzerCode: Fail # Web compiler specific
 JsInteropNonExternalConstructor/example: Fail # Web compiler specific
 JsInteropNonExternalMember/analyzerCode: Fail # Web compiler specific
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 83af639..db4e95d 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4667,9 +4667,6 @@
   template: "Named parameters for JS interop functions are only allowed in a factory constructor of an @anonymous JS class."
   tip: "Try replacing them with normal or optional parameters."
 
-JsInteropNativeClassInAnnotation:
-  template: "JS interop class '#name' conflicts with natively supported class '#name2' in '#string3'."
-
 JsInteropNonExternalConstructor:
   template: "JS interop classes do not support non-external constructors."
   tip: "Try annotating with `external`."
@@ -4931,4 +4928,4 @@
   exampleAllowMoreCodes: true
   analyzerCode: UNEXPECTED_TOKEN
   script:
-    - "late int x;"
+    - "late int x;"
\ No newline at end of file
diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt
index d926797..debea18 100644
--- a/pkg/front_end/test/spell_checking_list_messages.txt
+++ b/pkg/front_end/test/spell_checking_list_messages.txt
@@ -40,7 +40,6 @@
 name.stack
 nameokempty
 native('native
-natively
 nativetype
 nnbd
 nosuchmethod
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 8c80c4f..14bcf2c 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,4 +1,6 @@
 # Changelog
+## 6.0.0-nullsafety-dev
+- Migrate to use null safety.
 
 ## 5.5.1
 - Fix issue where `VmService.onDone` could complete before the provided `DisposeHandler` had finished executing.
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index 0243d12..365cb7f 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -14,17 +14,14 @@
 }
 
 bool assertBool(bool obj) {
-  assertNotNull(obj);
   return obj;
 }
 
 int assertInt(int obj) {
-  assertNotNull(obj);
   return obj;
 }
 
 double assertDouble(double obj) {
-  assertNotNull(obj);
   return obj;
 }
 
@@ -55,13 +52,11 @@
 }
 
 String assertString(String obj) {
-  assertNotNull(obj);
   if (obj.isEmpty) throw 'expected non-zero length string';
   return obj;
 }
 
 vms.Success assertSuccess(vms.Success obj) {
-  assertNotNull(obj);
   if (obj.type != 'Success') throw 'expected Success';
   return obj;
 }
@@ -75,10 +70,10 @@
       event.kind == vms.EventKind.kBreakpointAdded ||
       event.kind == vms.EventKind.kBreakpointRemoved ||
       event.kind == vms.EventKind.kBreakpointResolved) {
-    assertBreakpoint(event.breakpoint);
+    assertBreakpoint(event.breakpoint!);
   }
   if (event.kind == vms.EventKind.kPauseBreakpoint) {
-    for (vms.Breakpoint elem in event.pauseBreakpoints) {
+    for (vms.Breakpoint elem in event.pauseBreakpoints!) {
       assertBreakpoint(elem);
     }
   }
@@ -94,18 +89,18 @@
     if (event.topFrame != null ||
         (event.kind != vms.EventKind.kPauseInterrupted &&
             event.kind != vms.EventKind.kResume)) {
-      assertFrame(event.topFrame);
+      assertFrame(event.topFrame!);
     }
   }
   if (event.kind == vms.EventKind.kPauseException) {
-    assertInstanceRef(event.exception);
+    assertInstanceRef(event.exception!);
   }
   if (event.kind == vms.EventKind.kPauseBreakpoint ||
       event.kind == vms.EventKind.kPauseInterrupted) {
-    assertBool(event.atAsyncSuspension);
+    assertBool(event.atAsyncSuspension!);
   }
   if (event.kind == vms.EventKind.kInspect) {
-    assertInstanceRef(event.inspectee);
+    assertInstanceRef(event.inspectee!);
   }
   return event;
 }
@@ -115,7 +110,7 @@
 vms.Event assertIsolateEvent(vms.Event event) {
   assertEvent(event);
   if (event.kind == vms.EventKind.kServiceExtensionAdded) {
-    assertString(event.extensionRPC);
+    assertString(event.extensionRPC!);
   }
   return event;
 }
@@ -250,7 +245,6 @@
 
 vms.AllocationProfile assertAllocationProfile(vms.AllocationProfile obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertListOfClassHeapStats(obj.members);
   assertMemoryUsage(obj.memoryUsage);
   return obj;
@@ -271,7 +265,6 @@
 
 vms.BoundVariable assertBoundVariable(vms.BoundVariable obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.name);
   if (obj.value is vms.InstanceRef) {
     assertInstanceRef(obj.value);
@@ -298,7 +291,6 @@
 
 vms.Breakpoint assertBreakpoint(vms.Breakpoint obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertInt(obj.breakpointNumber);
   assertBool(obj.resolved);
@@ -321,7 +313,6 @@
 
 vms.ClassRef assertClassRef(vms.ClassRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   return obj;
@@ -336,7 +327,6 @@
 
 vms.Class assertClass(vms.Class obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   assertBool(obj.isAbstract);
@@ -351,7 +341,6 @@
 
 vms.ClassHeapStats assertClassHeapStats(vms.ClassHeapStats obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertClassRef(obj.classRef);
   assertInt(obj.accumulatedSize);
   assertInt(obj.bytesCurrent);
@@ -370,14 +359,12 @@
 
 vms.ClassList assertClassList(vms.ClassList obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertListOfClassRef(obj.classes);
   return obj;
 }
 
 vms.CodeRef assertCodeRef(vms.CodeRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   assertCodeKind(obj.kind);
@@ -393,7 +380,6 @@
 
 vms.Code assertCode(vms.Code obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   assertCodeKind(obj.kind);
@@ -402,7 +388,6 @@
 
 vms.ContextRef assertContextRef(vms.ContextRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertInt(obj.length);
   return obj;
@@ -417,7 +402,6 @@
 
 vms.Context assertContext(vms.Context obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertInt(obj.length);
   assertListOfContextElement(obj.variables);
@@ -446,7 +430,6 @@
 
 vms.CpuSamples assertCpuSamples(vms.CpuSamples obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertInt(obj.samplePeriod);
   assertInt(obj.maxStackDepth);
   assertInt(obj.sampleCount);
@@ -476,7 +459,6 @@
 
 vms.ErrorRef assertErrorRef(vms.ErrorRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertErrorKind(obj.kind);
   assertString(obj.message);
@@ -492,7 +474,6 @@
 
 vms.Error assertError(vms.Error obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertErrorKind(obj.kind);
   assertString(obj.message);
@@ -501,7 +482,6 @@
 
 vms.Event assertEvent(vms.Event obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertEventKind(obj.kind);
   assertInt(obj.timestamp);
   return obj;
@@ -514,7 +494,6 @@
 
 vms.FieldRef assertFieldRef(vms.FieldRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   assertObjRef(obj.owner);
@@ -534,7 +513,6 @@
 
 vms.Field assertField(vms.Field obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   assertObjRef(obj.owner);
@@ -562,14 +540,12 @@
 
 vms.FlagList assertFlagList(vms.FlagList obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertListOfFlag(obj.flags);
   return obj;
 }
 
 vms.Frame assertFrame(vms.Frame obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertInt(obj.index);
   return obj;
 }
@@ -583,7 +559,6 @@
 
 vms.FuncRef assertFuncRef(vms.FuncRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   if (obj.owner is vms.LibraryRef) {
@@ -609,7 +584,6 @@
 
 vms.Func assertFunc(vms.Func obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   if (obj.owner is vms.LibraryRef) {
@@ -628,7 +602,6 @@
 
 vms.InstanceRef assertInstanceRef(vms.InstanceRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertInstanceKind(obj.kind);
   assertClassRef(obj.classRef);
@@ -644,7 +617,6 @@
 
 vms.Instance assertInstance(vms.Instance obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertInstanceKind(obj.kind);
   assertClassRef(obj.classRef);
@@ -653,7 +625,6 @@
 
 vms.IsolateRef assertIsolateRef(vms.IsolateRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.number);
   assertString(obj.name);
@@ -670,7 +641,6 @@
 
 vms.Isolate assertIsolate(vms.Isolate obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.number);
   assertString(obj.name);
@@ -696,7 +666,6 @@
 
 vms.IsolateGroupRef assertIsolateGroupRef(vms.IsolateGroupRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.number);
   assertString(obj.name);
@@ -714,7 +683,6 @@
 
 vms.IsolateGroup assertIsolateGroup(vms.IsolateGroup obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.number);
   assertString(obj.name);
@@ -725,7 +693,6 @@
 
 vms.InboundReferences assertInboundReferences(vms.InboundReferences obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertListOfInboundReference(obj.references);
   return obj;
 }
@@ -746,7 +713,6 @@
 
 vms.InstanceSet assertInstanceSet(vms.InstanceSet obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertInt(obj.totalCount);
   assertListOfObjRef(obj.instances);
   return obj;
@@ -754,7 +720,6 @@
 
 vms.LibraryRef assertLibraryRef(vms.LibraryRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   assertString(obj.uri);
@@ -770,7 +735,6 @@
 
 vms.Library assertLibrary(vms.Library obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   assertString(obj.uri);
@@ -802,7 +766,6 @@
 
 vms.LogRecord assertLogRecord(vms.LogRecord obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertInstanceRef(obj.message);
   assertInt(obj.time);
   assertInt(obj.level);
@@ -835,7 +798,6 @@
 
 vms.MemoryUsage assertMemoryUsage(vms.MemoryUsage obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertInt(obj.externalUsage);
   assertInt(obj.heapCapacity);
   assertInt(obj.heapUsage);
@@ -844,7 +806,6 @@
 
 vms.Message assertMessage(vms.Message obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertInt(obj.index);
   assertString(obj.name);
   assertString(obj.messageObjectId);
@@ -867,7 +828,6 @@
 
 vms.NullValRef assertNullValRef(vms.NullValRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertInstanceKind(obj.kind);
   assertClassRef(obj.classRef);
@@ -884,7 +844,6 @@
 
 vms.NullVal assertNullVal(vms.NullVal obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertInstanceKind(obj.kind);
   assertClassRef(obj.classRef);
@@ -894,7 +853,6 @@
 
 vms.ObjRef assertObjRef(vms.ObjRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   return obj;
 }
@@ -908,14 +866,12 @@
 
 vms.Obj assertObj(vms.Obj obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   return obj;
 }
 
 vms.PortList assertPortList(vms.PortList obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertListOfInstanceRef(obj.ports);
   return obj;
 }
@@ -940,7 +896,6 @@
 
 vms.ProtocolList assertProtocolList(vms.ProtocolList obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertListOfProtocol(obj.protocols);
   return obj;
 }
@@ -962,7 +917,6 @@
 
 vms.ProcessMemoryUsage assertProcessMemoryUsage(vms.ProcessMemoryUsage obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertProcessMemoryItem(obj.root);
   return obj;
 }
@@ -986,7 +940,6 @@
 
 vms.ReloadReport assertReloadReport(vms.ReloadReport obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertBool(obj.success);
   return obj;
 }
@@ -1007,7 +960,6 @@
 
 vms.RetainingPath assertRetainingPath(vms.RetainingPath obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertInt(obj.length);
   assertString(obj.gcRootType);
   assertListOfRetainingObject(obj.elements);
@@ -1016,13 +968,11 @@
 
 vms.Response assertResponse(vms.Response obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   return obj;
 }
 
 vms.Sentinel assertSentinel(vms.Sentinel obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertSentinelKind(obj.kind);
   assertString(obj.valueAsString);
   return obj;
@@ -1030,7 +980,6 @@
 
 vms.ScriptRef assertScriptRef(vms.ScriptRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.uri);
   return obj;
@@ -1045,7 +994,6 @@
 
 vms.Script assertScript(vms.Script obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.uri);
   assertLibraryRef(obj.library);
@@ -1054,14 +1002,12 @@
 
 vms.ScriptList assertScriptList(vms.ScriptList obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertListOfScriptRef(obj.scripts);
   return obj;
 }
 
 vms.SourceLocation assertSourceLocation(vms.SourceLocation obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertScriptRef(obj.script);
   assertInt(obj.tokenPos);
   return obj;
@@ -1069,7 +1015,6 @@
 
 vms.SourceReport assertSourceReport(vms.SourceReport obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertListOfSourceReportRange(obj.ranges);
   assertListOfScriptRef(obj.scripts);
   return obj;
@@ -1102,7 +1047,6 @@
 
 vms.Stack assertStack(vms.Stack obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertListOfFrame(obj.frames);
   assertListOfMessage(obj.messages);
   assertBool(obj.truncated);
@@ -1111,7 +1055,6 @@
 
 vms.Timeline assertTimeline(vms.Timeline obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertListOfTimelineEvent(obj.traceEvents);
   assertInt(obj.timeOriginMicros);
   assertInt(obj.timeExtentMicros);
@@ -1133,7 +1076,6 @@
 
 vms.TimelineFlags assertTimelineFlags(vms.TimelineFlags obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.recorderName);
   assertListOfString(obj.availableStreams);
   assertListOfString(obj.recordedStreams);
@@ -1142,14 +1084,12 @@
 
 vms.Timestamp assertTimestamp(vms.Timestamp obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertInt(obj.timestamp);
   return obj;
 }
 
 vms.TypeArgumentsRef assertTypeArgumentsRef(vms.TypeArgumentsRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   return obj;
@@ -1165,7 +1105,6 @@
 
 vms.TypeArguments assertTypeArguments(vms.TypeArguments obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.id);
   assertString(obj.name);
   assertListOfInstanceRef(obj.types);
@@ -1175,13 +1114,11 @@
 vms.UnresolvedSourceLocation assertUnresolvedSourceLocation(
     vms.UnresolvedSourceLocation obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   return obj;
 }
 
 vms.Version assertVersion(vms.Version obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertInt(obj.major);
   assertInt(obj.minor);
   return obj;
@@ -1189,7 +1126,6 @@
 
 vms.VMRef assertVMRef(vms.VMRef obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.name);
   return obj;
 }
@@ -1203,7 +1139,6 @@
 
 vms.VM assertVM(vms.VM obj) {
   assertNotNull(obj);
-  assertString(obj.type);
   assertString(obj.name);
   assertInt(obj.architectureBits);
   assertString(obj.hostCPU);
diff --git a/pkg/vm_service/example/vm_service_tester.dart b/pkg/vm_service/example/vm_service_tester.dart
index 75e94a5..e22d5fc 100644
--- a/pkg/vm_service/example/vm_service_tester.dart
+++ b/pkg/vm_service/example/vm_service_tester.dart
@@ -18,10 +18,10 @@
 final String host = 'localhost';
 final int port = 7575;
 
-VmService serviceClient;
+late VmService serviceClient;
 
 void main() {
-  Process process;
+  Process? process;
 
   tearDown(() {
     process?.kill();
@@ -43,11 +43,11 @@
     print('dart process started');
 
     // ignore: unawaited_futures
-    process.exitCode.then((code) => print('vm exited: ${code}'));
+    process!.exitCode.then((code) => print('vm exited: ${code}'));
     // ignore: strong_mode_down_cast_composite
-    process.stdout.transform(utf8.decoder).listen(print);
+    process!.stdout.transform(utf8.decoder).listen(print);
     // ignore: strong_mode_down_cast_composite
-    process.stderr.transform(utf8.decoder).listen(print);
+    process!.stderr.transform(utf8.decoder).listen(print);
 
     await Future.delayed(Duration(milliseconds: 500));
 
@@ -70,7 +70,7 @@
       // reserialize it back to the same exact representation (minus private
       // fields).
       var json = jsonDecode(str);
-      var originalJson = json['result'] as Map<String, dynamic>;
+      var originalJson = json['result'] as Map<String, dynamic>?;
       if (originalJson == null && json['method'] == 'streamNotify') {
         originalJson = json['params']['event'];
       }
@@ -84,7 +84,7 @@
 
       var reserializedJson = (instance as dynamic).toJson();
 
-      forEachNestedMap(originalJson, (obj) {
+      forEachNestedMap(originalJson!, (obj) {
         // Private fields that we don't reproduce
         obj.removeWhere((k, v) => k.startsWith('_'));
         // Extra fields that aren't specified and we don't reproduce
@@ -169,11 +169,11 @@
   otherClient.onEvent('Service').listen((e) async {
     if (e.service == serviceName && e.kind == EventKind.kServiceRegistered) {
       assert(e.alias == serviceAlias);
-      Response response = await serviceClient.callMethod(
-        e.method,
+      Response? response = await serviceClient.callMethod(
+        e.method!,
         args: <String, dynamic>{'input': movedValue},
       );
-      assert(response.json['output'] == movedValue);
+      assert(response.json!['output'] == movedValue);
       completer.complete();
     }
   });
@@ -184,23 +184,23 @@
 
 Future testScriptParse(IsolateRef isolateRef) async {
   final Isolate isolate = await serviceClient.getIsolate(isolateRef.id);
-  final Library rootLibrary =
-      await serviceClient.getObject(isolateRef.id, isolate.rootLib.id);
+  final Library rootLibrary = await serviceClient.getObject(
+      isolateRef.id, isolate.rootLib!.id) as Library;
   final ScriptRef scriptRef = rootLibrary.scripts.first;
 
   final Script script =
-      await serviceClient.getObject(isolateRef.id, scriptRef.id);
+      await serviceClient.getObject(isolateRef.id, scriptRef.id) as Script;
   print(script);
   print(script.uri);
   print(script.library);
-  print(script.source.length);
-  print(script.tokenPosTable.length);
+  print(script.source!.length);
+  print(script.tokenPosTable!.length);
 }
 
 Future testSourceReport(IsolateRef isolateRef) async {
   final Isolate isolate = await serviceClient.getIsolate(isolateRef.id);
-  final Library rootLibrary =
-      await serviceClient.getObject(isolateRef.id, isolate.rootLib.id);
+  final Library rootLibrary = await serviceClient.getObject(
+      isolateRef.id, isolate.rootLib!.id) as Library;
   final ScriptRef scriptRef = rootLibrary.scripts.first;
 
   // make sure some code has run
diff --git a/pkg/vm_service/lib/src/dart_io_extensions.dart b/pkg/vm_service/lib/src/dart_io_extensions.dart
index c184d3c..acbca2d 100644
--- a/pkg/vm_service/lib/src/dart_io_extensions.dart
+++ b/pkg/vm_service/lib/src/dart_io_extensions.dart
@@ -6,7 +6,6 @@
 
 import 'dart:collection';
 
-import 'package:meta/meta.dart';
 import 'package:vm_service/vm_service.dart';
 
 import 'vm_service.dart';
@@ -16,10 +15,12 @@
   static Map<String, Version> _isolateVersion = {};
 
   Future<Version> _version(String isolateId) async {
-    if (_isolateVersion[isolateId] == null) {
-      _isolateVersion[isolateId] = await getDartIOVersion(isolateId);
+    Version? version = _isolateVersion[isolateId];
+    if (version == null) {
+      version = await getDartIOVersion(isolateId);
+      _isolateVersion[isolateId] = version;
     }
-    return _isolateVersion[isolateId];
+    return version;
   }
 
   /// The `getDartIOVersion` RPC returns the available version of the dart:io
@@ -46,7 +47,7 @@
   /// If the state of the socket profiler is changed, a `SocketProfilingStateChange`
   /// event will be sent on the `Extension` stream.
   Future<SocketProfilingState> socketProfilingEnabled(String isolateId,
-      [bool enabled]) async {
+      [bool? enabled]) async {
     return _callHelper('ext.dart.io.socketProfilingEnabled', isolateId, args: {
       if (enabled != null) 'enabled': enabled,
     });
@@ -90,7 +91,7 @@
   /// If the value of `HttpClient.enableTimelineLogging` is changed, a
   /// `HttpTimelineLoggingStateChange` event will be sent on the `Extension` stream.
   Future<HttpTimelineLoggingState> httpEnableTimelineLogging(String isolateId,
-      [bool enabled]) async {
+      [bool? enabled]) async {
     final version = await _version(isolateId);
     // Parameter name changed in version 1.4.
     final enableKey =
@@ -139,7 +140,7 @@
         },
       );
 
-  Future<T> _callHelper<T>(String method, String isolateId,
+  Future<T> _callHelper<T>(String method, String? isolateId,
       {Map args = const {}}) {
     if (!_factoriesRegistered) {
       _registerFactories();
@@ -170,7 +171,7 @@
 }
 
 class SocketStatistic {
-  static SocketStatistic parse(Map json) =>
+  static SocketStatistic? parse(Map<String, dynamic>? json) =>
       json == null ? null : SocketStatistic._fromJson(json);
 
   /// The unique ID associated with this socket.
@@ -219,43 +220,54 @@
 
 /// A [SocketProfile] provides information about statistics of sockets.
 class SocketProfile extends Response {
-  static SocketProfile parse(Map json) =>
+  static SocketProfile? parse(Map<String, dynamic>? json) =>
       json == null ? null : SocketProfile._fromJson(json);
 
-  /// List of socket statistics.
-  List<SocketStatistic> sockets;
+  @override
+  String get type => 'SocketProfile';
 
-  SocketProfile({@required this.sockets});
+  /// List of socket statistics.
+  late final List<SocketStatistic> sockets;
+
+  SocketProfile({required this.sockets});
 
   SocketProfile._fromJson(Map<String, dynamic> json) {
     // TODO(bkonyi): make this part of the vm_service.dart library so we can
     // call super._fromJson.
-    type = json['type'];
     sockets = List<SocketStatistic>.from(
-        createServiceObject(json['sockets'], const ['SocketStatistic']) ?? []);
+        createServiceObject(json['sockets'], const ['SocketStatistic'])
+                as List? ??
+            []);
   }
 }
 
 /// A [Response] containing the enabled state of a service extension.
 abstract class _State extends Response {
-  _State({@required this.enabled});
+  _State({required this.enabled}) : _type = 'State';
 
   // TODO(bkonyi): make this part of the vm_service.dart library so we can
   // call super._fromJson.
-  _State._fromJson(Map<String, dynamic> json) : enabled = json['enabled'] {
-    type = json['type'];
-  }
+  _State._fromJson(Map<String, dynamic> json)
+      : enabled = json['enabled'],
+        _type = json['type'];
+
+  @override
+  String get type => _type;
 
   final bool enabled;
+  final String _type;
 }
 
 /// A [HttpTimelineLoggingState] provides information about the current state of HTTP
 /// request logging for a given isolate.
 class HttpTimelineLoggingState extends _State {
-  static HttpTimelineLoggingState parse(Map json) =>
+  static HttpTimelineLoggingState? parse(Map<String, dynamic>? json) =>
       json == null ? null : HttpTimelineLoggingState._fromJson(json);
 
-  HttpTimelineLoggingState({@required bool enabled}) : super(enabled: enabled);
+  @override
+  String get type => 'HttpTimelineLoggingState';
+
+  HttpTimelineLoggingState({required bool enabled}) : super(enabled: enabled);
 
   HttpTimelineLoggingState._fromJson(Map<String, dynamic> json)
       : super._fromJson(json);
@@ -264,10 +276,10 @@
 /// A [SocketProfilingState] provides information about the current state of
 /// socket profiling for a given isolate.
 class SocketProfilingState extends _State {
-  static SocketProfilingState parse(Map json) =>
+  static SocketProfilingState? parse(Map<String, dynamic>? json) =>
       json == null ? null : SocketProfilingState._fromJson(json);
 
-  SocketProfilingState({@required bool enabled}) : super(enabled: enabled);
+  SocketProfilingState({required bool enabled}) : super(enabled: enabled);
 
   SocketProfilingState._fromJson(Map<String, dynamic> json)
       : super._fromJson(json);
@@ -275,12 +287,12 @@
 
 /// A [SpawnedProcessRef] contains identifying information about a spawned process.
 class SpawnedProcessRef {
-  static SpawnedProcessRef parse(Map json) =>
+  static SpawnedProcessRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : SpawnedProcessRef._fromJson(json);
 
   SpawnedProcessRef({
-    @required this.id,
-    @required this.name,
+    required this.id,
+    required this.name,
   });
 
   SpawnedProcessRef._fromJson(Map<String, dynamic> json)
@@ -301,16 +313,16 @@
 
 /// A [SpawnedProcess] contains startup information of a spawned process.
 class SpawnedProcess extends Response implements SpawnedProcessRef {
-  static SpawnedProcess parse(Map json) =>
+  static SpawnedProcess? parse(Map<String, dynamic>? json) =>
       json == null ? null : SpawnedProcess._fromJson(json);
 
   SpawnedProcess({
-    @required this.id,
-    @required this.name,
-    @required this.pid,
-    @required this.startedAt,
-    @required List<String> arguments,
-    @required this.workingDirectory,
+    required this.id,
+    required this.name,
+    required this.pid,
+    required this.startedAt,
+    required List<String> arguments,
+    required this.workingDirectory,
   }) : _arguments = arguments;
 
   SpawnedProcess._fromJson(Map<String, dynamic> json)
@@ -322,11 +334,11 @@
         pid = json['pid'],
         startedAt = json['startedAt'],
         _arguments = List<String>.from(
-            createServiceObject(json['arguments'], const ['String']) as List ??
-                []),
-        workingDirectory = json['workingDirectory'] {
-    type = json['type'];
-  }
+            createServiceObject(json['arguments'], const ['String']) as List),
+        workingDirectory = json['workingDirectory'];
+
+  @override
+  String get type => 'SpawnedProcess';
 
   /// The unique ID associated with this process.
   final int id;
@@ -349,10 +361,10 @@
 }
 
 class SpawnedProcessList extends Response {
-  static SpawnedProcessList parse(Map json) =>
+  static SpawnedProcessList? parse(Map<String, dynamic>? json) =>
       json == null ? null : SpawnedProcessList._fromJson(json);
 
-  SpawnedProcessList({@required List<SpawnedProcessRef> processes})
+  SpawnedProcessList({required List<SpawnedProcessRef> processes})
       : _processes = processes;
 
   SpawnedProcessList._fromJson(Map<String, dynamic> json)
@@ -361,10 +373,10 @@
         // call super._fromJson.
         _processes = List<SpawnedProcessRef>.from(
             createServiceObject(json['processes'], const ['SpawnedProcessRef'])
-                    as List ??
-                []) {
-    type = json['type'];
-  }
+                as List);
+
+  @override
+  String get type => 'SpawnedProcessList';
 
   /// A list of processes spawned through dart:io on a given isolate.
   List<SpawnedProcessRef> get processes => UnmodifiableListView(_processes);
@@ -373,12 +385,12 @@
 
 /// A [OpenFileRef] contains identifying information about a currently opened file.
 class OpenFileRef {
-  static OpenFileRef parse(Map json) =>
+  static OpenFileRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : OpenFileRef._fromJson(json);
 
   OpenFileRef({
-    @required this.id,
-    @required this.name,
+    required this.id,
+    required this.name,
   });
 
   OpenFileRef._fromJson(Map<String, dynamic> json)
@@ -399,18 +411,18 @@
 
 /// A [File] contains information about reads and writes to a currently opened file.
 class OpenFile extends Response implements OpenFileRef {
-  static OpenFile parse(Map json) =>
+  static OpenFile? parse(Map<String, dynamic>? json) =>
       json == null ? null : OpenFile._fromJson(json);
 
   OpenFile({
-    @required this.id,
-    @required this.name,
-    @required this.readBytes,
-    @required this.writeBytes,
-    @required this.readCount,
-    @required this.writeCount,
-    @required this.lastReadTime,
-    @required this.lastWriteTime,
+    required this.id,
+    required this.name,
+    required this.readBytes,
+    required this.writeBytes,
+    required this.readCount,
+    required this.writeCount,
+    required this.lastReadTime,
+    required this.lastWriteTime,
   });
 
   OpenFile._fromJson(Map<String, dynamic> json)
@@ -426,9 +438,10 @@
         lastReadTime =
             DateTime.fromMillisecondsSinceEpoch(json['lastReadTime']),
         lastWriteTime =
-            DateTime.fromMillisecondsSinceEpoch(json['lastWriteTime']) {
-    type = json['type'];
-  }
+            DateTime.fromMillisecondsSinceEpoch(json['lastWriteTime']);
+
+  @override
+  String get type => 'OpenFile';
 
   /// The unique ID associated with this file.
   final int id;
@@ -456,20 +469,20 @@
 }
 
 class OpenFileList extends Response {
-  static OpenFileList parse(Map json) =>
+  static OpenFileList? parse(Map<String, dynamic>? json) =>
       json == null ? null : OpenFileList._fromJson(json);
 
-  OpenFileList({@required List<OpenFileRef> files}) : _files = files;
+  OpenFileList({required List<OpenFileRef> files}) : _files = files;
 
   OpenFileList._fromJson(Map<String, dynamic> json)
       :
         // TODO(bkonyi): make this part of the vm_service.dart library so we can
         // call super._fromJson.
         _files = List<OpenFileRef>.from(
-            createServiceObject(json['files'], const ['OpenFileRef']) as List ??
-                []) {
-    type = json['type'];
-  }
+            createServiceObject(json['files'], const ['OpenFileRef']) as List);
+
+  @override
+  String get type => 'OpenFileList';
 
   /// A list of all files opened through dart:io on a given isolate.
   List<OpenFileRef> get files => UnmodifiableListView(_files);
diff --git a/pkg/vm_service/lib/src/helpers.dart b/pkg/vm_service/lib/src/helpers.dart
index 0d14c16..a92c70b 100644
--- a/pkg/vm_service/lib/src/helpers.dart
+++ b/pkg/vm_service/lib/src/helpers.dart
@@ -6,7 +6,7 @@
 
 class IsolateHelper {
   static List<TagCounter> getTagCounters(Isolate isolate) {
-    Map m = isolate.json['_tagCounters'];
+    Map m = isolate.json!['_tagCounters']!;
     List<String> names = m['names'];
     List<int> counters = m['counters'];
 
diff --git a/pkg/vm_service/lib/src/service_extension_registry.dart b/pkg/vm_service/lib/src/service_extension_registry.dart
index 9ec1514..6de71cd 100644
--- a/pkg/vm_service/lib/src/service_extension_registry.dart
+++ b/pkg/vm_service/lib/src/service_extension_registry.dart
@@ -44,7 +44,7 @@
   ///
   /// The result of this function should not be stored, because clients may
   /// shut down at any time.
-  VmServerConnection clientFor(String extension) =>
+  VmServerConnection? clientFor(String extension) =>
       _extensionToConnection[extension];
 
   /// All of the currently registered extensions
diff --git a/pkg/vm_service/lib/src/snapshot_graph.dart b/pkg/vm_service/lib/src/snapshot_graph.dart
index bad549e..e237dd7 100644
--- a/pkg/vm_service/lib/src/snapshot_graph.dart
+++ b/pkg/vm_service/lib/src/snapshot_graph.dart
@@ -100,8 +100,8 @@
   /// The name of the field.
   String get name => _name;
 
-  int _index;
-  String _name;
+  int _index = -1;
+  String _name = '';
 
   HeapSnapshotField._read(_ReadStream reader) {
     // flags (reserved)
@@ -129,10 +129,10 @@
   /// The list of fields in the class.
   List<HeapSnapshotField> get fields => _fields;
 
-  String _name;
-  String _libraryName;
-  Uri _libraryUri;
-  List<HeapSnapshotField> _fields = <HeapSnapshotField>[];
+  String _name = '';
+  String _libraryName = '';
+  late final Uri _libraryUri;
+  final List<HeapSnapshotField> _fields = <HeapSnapshotField>[];
 
   HeapSnapshotClass._read(_ReadStream reader) {
     // flags (reserved).
@@ -170,10 +170,10 @@
   /// A list of 1-origin indicies into [HeapSnapshotGraph.objects].
   List<int> get references => _references;
 
-  int _classId;
-  int _shallowSize;
-  dynamic _data;
-  List<int> _references = <int>[];
+  int _classId = -1;
+  int _shallowSize = -1;
+  late final dynamic _data;
+  final List<int> _references = <int>[];
 
   HeapSnapshotObject._read(_ReadStream reader) {
     _classId = reader.readUnsigned();
@@ -238,15 +238,15 @@
   List<HeapSnapshotExternalProperty> get externalProperties =>
       _externalProperties;
 
-  String _name;
-  int _flags;
-  int _shallowSize;
-  int _capacity;
-  int _externalSize;
-  List<HeapSnapshotClass> _classes = <HeapSnapshotClass>[];
-  int _referenceCount;
-  List<HeapSnapshotObject> _objects = <HeapSnapshotObject>[];
-  List<HeapSnapshotExternalProperty> _externalProperties =
+  String _name = '';
+  int _flags = -1;
+  int _shallowSize = -1;
+  int _capacity = -1;
+  int _externalSize = -1;
+  final List<HeapSnapshotClass> _classes = <HeapSnapshotClass>[];
+  int _referenceCount = -1;
+  final List<HeapSnapshotObject> _objects = <HeapSnapshotObject>[];
+  final List<HeapSnapshotExternalProperty> _externalProperties =
       <HeapSnapshotExternalProperty>[];
 
   /// Requests a heap snapshot for a given isolate and builds a
@@ -260,10 +260,10 @@
 
     final completer = Completer<HeapSnapshotGraph>();
     final chunks = <ByteData>[];
-    StreamSubscription streamSubscription;
+    late StreamSubscription streamSubscription;
     streamSubscription = service.onHeapSnapshotEvent.listen((e) async {
-      chunks.add(e.data);
-      if (e.last) {
+      chunks.add(e.data!);
+      if (e.last!) {
         await service.streamCancel(EventStreams.kHeapSnapshot);
         await streamSubscription.cancel();
         completer.complete(HeapSnapshotGraph.fromChunks(chunks));
diff --git a/pkg/vm_service/lib/src/stream_helpers.dart b/pkg/vm_service/lib/src/stream_helpers.dart
index 474c417..b7b5515 100644
--- a/pkg/vm_service/lib/src/stream_helpers.dart
+++ b/pkg/vm_service/lib/src/stream_helpers.dart
@@ -35,12 +35,12 @@
         ? _next.asBroadcastStream()
         : _next;
 
-    StreamSubscription<T> subscription;
+    StreamSubscription<T>? subscription;
     var currentStream = first;
     var firstDone = false;
     var secondDone = false;
 
-    Function currentDoneHandler;
+    late Function currentDoneHandler;
 
     listen() {
       subscription = currentStream.listen(controller.add,
@@ -64,21 +64,22 @@
     controller.onListen = () {
       assert(subscription == null);
       listen();
+      final sub = subscription!;
       if (!first.isBroadcast) {
         controller
           ..onPause = () {
-            if (!firstDone || !next.isBroadcast) return subscription.pause();
-            subscription.cancel();
+            if (!firstDone || !next.isBroadcast) return sub.pause();
+            sub.cancel();
             subscription = null;
           }
           ..onResume = () {
-            if (!firstDone || !next.isBroadcast) return subscription.resume();
+            if (!firstDone || !next.isBroadcast) return sub.resume();
             listen();
           };
       }
       controller.onCancel = () {
         if (secondDone) return null;
-        var toCancel = subscription;
+        var toCancel = subscription!;
         subscription = null;
         return toCancel.cancel();
       };
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index 446c5e4..12d1b61 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -12,8 +12,6 @@
 import 'dart:convert' show base64, jsonDecode, jsonEncode, utf8;
 import 'dart:typed_data';
 
-import 'package:meta/meta.dart';
-
 import 'service_extension_registry.dart';
 
 export 'service_extension_registry.dart' show ServiceExtensionRegistry;
@@ -41,13 +39,13 @@
 bool _isNullInstance(Map json) =>
     ((json['type'] == '@Instance') && (json['kind'] == 'Null'));
 
-Object createServiceObject(dynamic json, List<String> expectedTypes) {
+Object? createServiceObject(dynamic json, List<String> expectedTypes) {
   if (json == null) return null;
 
   if (json is List) {
     return json.map((e) => createServiceObject(e, expectedTypes)).toList();
   } else if (json is Map) {
-    String type = json['type'];
+    String? type = json['type'];
 
     // Not a Response type.
     if (type == null) {
@@ -62,10 +60,11 @@
       // be returned.
       return null;
     }
-    if (_typeFactories[type] == null) {
+    final typeFactory = _typeFactories[type];
+    if (typeFactory == null) {
       return null;
     } else {
-      return _typeFactories[type](json);
+      return typeFactory(json);
     }
   } else {
     // Handle simple types.
@@ -89,7 +88,7 @@
   }
 }
 
-void _setIfNotNull(Map<String, Object> json, String key, Object value) {
+void _setIfNotNull(Map<String, dynamic> json, String key, Object? value) {
   if (value == null) return;
   json[key] = value;
 }
@@ -250,7 +249,7 @@
 
   /// Handler for calling extra service extensions.
   Future<Response> callServiceExtension(String method,
-      {String isolateId, Map args});
+      {String? isolateId, Map<String, dynamic>? args});
 
   /// The `addBreakpoint` RPC is used to add a breakpoint at a specific line of
   /// some script.
@@ -284,7 +283,7 @@
     String isolateId,
     String scriptId,
     int line, {
-    int column,
+    int? column,
   });
 
   /// The `addBreakpoint` RPC is used to add a breakpoint at a specific line of
@@ -321,7 +320,7 @@
     String isolateId,
     String scriptUri,
     int line, {
-    int column,
+    int? column,
   });
 
   /// The `addBreakpointAtEntry` RPC is used to add a breakpoint at the
@@ -398,7 +397,7 @@
     String targetId,
     String selector,
     List<String> argumentIds, {
-    bool disableBreakpoints,
+    bool? disableBreakpoints,
   });
 
   /// The `evaluate` RPC is used to evaluate an expression in the context of
@@ -443,8 +442,8 @@
     String isolateId,
     String targetId,
     String expression, {
-    Map<String, String> scope,
-    bool disableBreakpoints,
+    Map<String, String>? scope,
+    bool? disableBreakpoints,
   });
 
   /// The `evaluateInFrame` RPC is used to evaluate an expression in the context
@@ -481,8 +480,8 @@
     String isolateId,
     int frameIndex,
     String expression, {
-    Map<String, String> scope,
-    bool disableBreakpoints,
+    Map<String, String>? scope,
+    bool? disableBreakpoints,
   });
 
   /// The `getAllocationProfile` RPC is used to retrieve allocation information
@@ -501,7 +500,7 @@
   /// This method will throw a [SentinelException] in the case a [Sentinel] is
   /// returned.
   Future<AllocationProfile> getAllocationProfile(String isolateId,
-      {bool reset, bool gc});
+      {bool? reset, bool? gc});
 
   /// The `getClassList` RPC is used to retrieve a `ClassList` containing all
   /// classes for an isolate based on the isolate's `isolateId`.
@@ -686,8 +685,8 @@
   Future<Obj> getObject(
     String isolateId,
     String objectId, {
-    int offset,
-    int count,
+    int? offset,
+    int? count,
   });
 
   /// The `getPorts` RPC is used to retrieve the list of `ReceivePort` instances
@@ -746,7 +745,7 @@
   ///
   /// This method will throw a [SentinelException] in the case a [Sentinel] is
   /// returned.
-  Future<Stack> getStack(String isolateId, {int limit});
+  Future<Stack> getStack(String isolateId, {int? limit});
 
   /// The `getSupportedProtocols` RPC is used to determine which protocols are
   /// supported by the current server.
@@ -801,10 +800,10 @@
     String isolateId,
     /*List<SourceReportKind>*/
     List<String> reports, {
-    String scriptId,
-    int tokenPos,
-    int endTokenPos,
-    bool forceCompile,
+    String? scriptId,
+    int? tokenPos,
+    int? endTokenPos,
+    bool? forceCompile,
   });
 
   /// The `getVersion` RPC is used to determine what version of the Service
@@ -838,7 +837,8 @@
   /// or Macos or Systrace, an [RPC error] with error code `114`, `invalid
   /// timeline request`, will be returned as timeline events are handled by the
   /// OS in these modes.
-  Future<Timeline> getVMTimeline({int timeOriginMicros, int timeExtentMicros});
+  Future<Timeline> getVMTimeline(
+      {int? timeOriginMicros, int? timeExtentMicros});
 
   /// The `getVMTimelineFlags` RPC returns information about the current VM
   /// timeline configuration.
@@ -917,10 +917,10 @@
   /// returned.
   Future<ReloadReport> reloadSources(
     String isolateId, {
-    bool force,
-    bool pause,
-    String rootLibUri,
-    String packagesUri,
+    bool? force,
+    bool? pause,
+    String? rootLibUri,
+    String? packagesUri,
   });
 
   /// The `removeBreakpoint` RPC is used to remove a breakpoint by its `id`.
@@ -981,7 +981,7 @@
   /// This method will throw a [SentinelException] in the case a [Sentinel] is
   /// returned.
   Future<Success> resume(String isolateId,
-      {/*StepOption*/ String step, int frameIndex});
+      {/*StepOption*/ String? step, int? frameIndex});
 
   /// The `setExceptionPauseMode` RPC is used to control if an isolate pauses
   /// when an exception is thrown.
@@ -1120,14 +1120,14 @@
 }
 
 class _PendingServiceRequest {
-  Future<Map<String, Object>> get future => _completer.future;
-  final _completer = Completer<Map<String, Object>>();
+  Future<Map<String, Object?>> get future => _completer.future;
+  final _completer = Completer<Map<String, Object?>>();
 
   final dynamic originalId;
 
   _PendingServiceRequest(this.originalId);
 
-  void complete(Map<String, Object> response) {
+  void complete(Map<String, Object?> response) {
     response['id'] = originalId;
     _completer.complete(response);
   }
@@ -1141,7 +1141,7 @@
 /// instances.
 class VmServerConnection {
   final Stream<Map<String, Object>> _requestStream;
-  final StreamSink<Map<String, Object>> _responseSink;
+  final StreamSink<Map<String, Object?>> _responseSink;
   final ServiceExtensionRegistry _serviceExtensionRegistry;
   final VmServiceInterface _serviceImplementation;
 
@@ -1152,8 +1152,8 @@
   final _streamSubscriptions = <String, StreamSubscription>{};
 
   /// Completes when [_requestStream] is done.
-  Future get done => _doneCompleter.future;
-  final _doneCompleter = Completer<Null>();
+  Future<void> get done => _doneCompleter.future;
+  final _doneCompleter = Completer<void>();
 
   /// Pending service extension requests to this client by id.
   final _pendingServiceExtensionRequests = <dynamic, _PendingServiceRequest>{};
@@ -1170,13 +1170,13 @@
   ///
   /// We don't attempt to do any serialization or deserialization of the
   /// request or response in this case
-  Future<Map<String, Object>> _forwardServiceExtensionRequest(
-      Map<String, Object> request) {
-    var originalId = request['id'];
-    request = Map.of(request);
+  Future<Map<String, Object?>> _forwardServiceExtensionRequest(
+      Map<String, Object?> request) {
+    final originalId = request['id'];
+    request = Map<String, Object?>.of(request);
     // Modify the request ID to ensure we don't have conflicts between
     // multiple clients ids.
-    var newId = '${_nextServiceRequestId++}:$originalId';
+    final newId = '${_nextServiceRequestId++}:$originalId';
     request['id'] = newId;
     var pendingRequest = _PendingServiceRequest(originalId);
     _pendingServiceExtensionRequests[newId] = pendingRequest;
@@ -1184,31 +1184,31 @@
     return pendingRequest.future;
   }
 
-  void _delegateRequest(Map<String, Object> request) async {
+  void _delegateRequest(Map<String, Object?> request) async {
     try {
       var id = request['id'];
       // Check if this is actually a response to a pending request.
       if (_pendingServiceExtensionRequests.containsKey(id)) {
-        final pending = _pendingServiceExtensionRequests[id];
-        pending.complete(Map.of(request));
+        final pending = _pendingServiceExtensionRequests[id]!;
+        pending.complete(Map<String, Object?>.of(request));
         return;
       }
-      var method = request['method'] as String;
+      final method = request['method'] as String?;
       if (method == null) {
         throw RPCError(
             null, RPCError.kInvalidRequest, 'Invalid Request', request);
       }
-      var params = request['params'] as Map;
-      Response response;
+      final params = request['params'] as Map<String, dynamic>?;
+      late Response response;
 
       switch (method) {
         case 'registerService':
-          _serviceExtensionRegistry.registerExtension(params['service'], this);
+          _serviceExtensionRegistry.registerExtension(params!['service'], this);
           response = Success();
           break;
         case 'addBreakpoint':
           response = await _serviceImplementation.addBreakpoint(
-            params['isolateId'],
+            params!['isolateId'],
             params['scriptId'],
             params['line'],
             column: params['column'],
@@ -1216,7 +1216,7 @@
           break;
         case 'addBreakpointWithScriptUri':
           response = await _serviceImplementation.addBreakpointWithScriptUri(
-            params['isolateId'],
+            params!['isolateId'],
             params['scriptUri'],
             params['line'],
             column: params['column'],
@@ -1224,13 +1224,13 @@
           break;
         case 'addBreakpointAtEntry':
           response = await _serviceImplementation.addBreakpointAtEntry(
-            params['isolateId'],
+            params!['isolateId'],
             params['functionId'],
           );
           break;
         case 'clearCpuSamples':
           response = await _serviceImplementation.clearCpuSamples(
-            params['isolateId'],
+            params!['isolateId'],
           );
           break;
         case 'clearVMTimeline':
@@ -1238,7 +1238,7 @@
           break;
         case 'invoke':
           response = await _serviceImplementation.invoke(
-            params['isolateId'],
+            params!['isolateId'],
             params['targetId'],
             params['selector'],
             List<String>.from(params['argumentIds'] ?? []),
@@ -1247,7 +1247,7 @@
           break;
         case 'evaluate':
           response = await _serviceImplementation.evaluate(
-            params['isolateId'],
+            params!['isolateId'],
             params['targetId'],
             params['expression'],
             scope: params['scope']?.cast<String, String>(),
@@ -1256,7 +1256,7 @@
           break;
         case 'evaluateInFrame':
           response = await _serviceImplementation.evaluateInFrame(
-            params['isolateId'],
+            params!['isolateId'],
             params['frameIndex'],
             params['expression'],
             scope: params['scope']?.cast<String, String>(),
@@ -1265,19 +1265,19 @@
           break;
         case 'getAllocationProfile':
           response = await _serviceImplementation.getAllocationProfile(
-            params['isolateId'],
+            params!['isolateId'],
             reset: params['reset'],
             gc: params['gc'],
           );
           break;
         case 'getClassList':
           response = await _serviceImplementation.getClassList(
-            params['isolateId'],
+            params!['isolateId'],
           );
           break;
         case 'getCpuSamples':
           response = await _serviceImplementation.getCpuSamples(
-            params['isolateId'],
+            params!['isolateId'],
             params['timeOriginMicros'],
             params['timeExtentMicros'],
           );
@@ -1287,46 +1287,46 @@
           break;
         case 'getInboundReferences':
           response = await _serviceImplementation.getInboundReferences(
-            params['isolateId'],
+            params!['isolateId'],
             params['targetId'],
             params['limit'],
           );
           break;
         case 'getInstances':
           response = await _serviceImplementation.getInstances(
-            params['isolateId'],
+            params!['isolateId'],
             params['objectId'],
             params['limit'],
           );
           break;
         case 'getIsolate':
           response = await _serviceImplementation.getIsolate(
-            params['isolateId'],
+            params!['isolateId'],
           );
           break;
         case 'getIsolateGroup':
           response = await _serviceImplementation.getIsolateGroup(
-            params['isolateGroupId'],
+            params!['isolateGroupId'],
           );
           break;
         case 'getMemoryUsage':
           response = await _serviceImplementation.getMemoryUsage(
-            params['isolateId'],
+            params!['isolateId'],
           );
           break;
         case 'getIsolateGroupMemoryUsage':
           response = await _serviceImplementation.getIsolateGroupMemoryUsage(
-            params['isolateGroupId'],
+            params!['isolateGroupId'],
           );
           break;
         case 'getScripts':
           response = await _serviceImplementation.getScripts(
-            params['isolateId'],
+            params!['isolateId'],
           );
           break;
         case 'getObject':
           response = await _serviceImplementation.getObject(
-            params['isolateId'],
+            params!['isolateId'],
             params['objectId'],
             offset: params['offset'],
             count: params['count'],
@@ -1334,12 +1334,12 @@
           break;
         case 'getPorts':
           response = await _serviceImplementation.getPorts(
-            params['isolateId'],
+            params!['isolateId'],
           );
           break;
         case 'getRetainingPath':
           response = await _serviceImplementation.getRetainingPath(
-            params['isolateId'],
+            params!['isolateId'],
             params['targetId'],
             params['limit'],
           );
@@ -1349,7 +1349,7 @@
           break;
         case 'getStack':
           response = await _serviceImplementation.getStack(
-            params['isolateId'],
+            params!['isolateId'],
             limit: params['limit'],
           );
           break;
@@ -1358,7 +1358,7 @@
           break;
         case 'getSourceReport':
           response = await _serviceImplementation.getSourceReport(
-            params['isolateId'],
+            params!['isolateId'],
             List<String>.from(params['reports'] ?? []),
             scriptId: params['scriptId'],
             tokenPos: params['tokenPos'],
@@ -1374,7 +1374,7 @@
           break;
         case 'getVMTimeline':
           response = await _serviceImplementation.getVMTimeline(
-            timeOriginMicros: params['timeOriginMicros'],
+            timeOriginMicros: params!['timeOriginMicros'],
             timeExtentMicros: params['timeExtentMicros'],
           );
           break;
@@ -1386,17 +1386,17 @@
           break;
         case 'pause':
           response = await _serviceImplementation.pause(
-            params['isolateId'],
+            params!['isolateId'],
           );
           break;
         case 'kill':
           response = await _serviceImplementation.kill(
-            params['isolateId'],
+            params!['isolateId'],
           );
           break;
         case 'reloadSources':
           response = await _serviceImplementation.reloadSources(
-            params['isolateId'],
+            params!['isolateId'],
             force: params['force'],
             pause: params['pause'],
             rootLibUri: params['rootLibUri'],
@@ -1405,59 +1405,59 @@
           break;
         case 'removeBreakpoint':
           response = await _serviceImplementation.removeBreakpoint(
-            params['isolateId'],
+            params!['isolateId'],
             params['breakpointId'],
           );
           break;
         case 'requestHeapSnapshot':
           response = await _serviceImplementation.requestHeapSnapshot(
-            params['isolateId'],
+            params!['isolateId'],
           );
           break;
         case 'resume':
           response = await _serviceImplementation.resume(
-            params['isolateId'],
+            params!['isolateId'],
             step: params['step'],
             frameIndex: params['frameIndex'],
           );
           break;
         case 'setExceptionPauseMode':
           response = await _serviceImplementation.setExceptionPauseMode(
-            params['isolateId'],
+            params!['isolateId'],
             params['mode'],
           );
           break;
         case 'setFlag':
           response = await _serviceImplementation.setFlag(
-            params['name'],
+            params!['name'],
             params['value'],
           );
           break;
         case 'setLibraryDebuggable':
           response = await _serviceImplementation.setLibraryDebuggable(
-            params['isolateId'],
+            params!['isolateId'],
             params['libraryId'],
             params['isDebuggable'],
           );
           break;
         case 'setName':
           response = await _serviceImplementation.setName(
-            params['isolateId'],
+            params!['isolateId'],
             params['name'],
           );
           break;
         case 'setVMName':
           response = await _serviceImplementation.setVMName(
-            params['name'],
+            params!['name'],
           );
           break;
         case 'setVMTimelineFlags':
           response = await _serviceImplementation.setVMTimelineFlags(
-            List<String>.from(params['recordedStreams'] ?? []),
+            List<String>.from(params!['recordedStreams'] ?? []),
           );
           break;
         case 'streamCancel':
-          var id = params['streamId'];
+          var id = params!['streamId'];
           var existing = _streamSubscriptions.remove(id);
           if (existing == null) {
             throw RPCError.withDetails(
@@ -1471,7 +1471,7 @@
           response = Success();
           break;
         case 'streamListen':
-          var id = params['streamId'];
+          var id = params!['streamId'];
           if (_streamSubscriptions.containsKey(id)) {
             throw RPCError.withDetails(
               'streamListen',
@@ -1497,7 +1497,7 @@
           response = Success();
           break;
         default:
-          var registeredClient = _serviceExtensionRegistry.clientFor(method);
+          final registeredClient = _serviceExtensionRegistry.clientFor(method);
           if (registeredClient != null) {
             // Check for any client which has registered this extension, if we
             // have one then delegate the request to that client.
@@ -1509,8 +1509,9 @@
           } else if (method.startsWith('ext.')) {
             // Remaining methods with `ext.` are assumed to be registered via
             // dart:developer, which the service implementation handles.
-            var args = params == null ? null : Map.of(params);
-            var isolateId = args?.remove('isolateId');
+            final args =
+                params == null ? null : Map<String, dynamic>.of(params);
+            final isolateId = args?.remove('isolateId');
             response = await _serviceImplementation.callServiceExtension(method,
                 isolateId: isolateId, args: args);
           } else {
@@ -1518,16 +1519,13 @@
                 method, RPCError.kMethodNotFound, 'Method not found', request);
           }
       }
-      if (response == null) {
-        throw StateError('Invalid null response from service');
-      }
       _responseSink.add({
         'jsonrpc': '2.0',
         'id': id,
         'result': response.toJson(),
       });
     } catch (e, st) {
-      var error = e is RPCError
+      final error = e is RPCError
           ? e.toMap()
           : {
               'code': RPCError.kInternalError,
@@ -1544,13 +1542,13 @@
 }
 
 class VmService implements VmServiceInterface {
-  StreamSubscription _streamSub;
-  Function _writeMessage;
+  late final StreamSubscription _streamSub;
+  late final Function _writeMessage;
   int _id = 0;
   Map<String, Completer> _completers = {};
   Map<String, String> _methodCalls = {};
   Map<String, ServiceCallback> _services = {};
-  Log _log;
+  late final Log _log;
 
   StreamController<String> _onSend = StreamController.broadcast(sync: true);
   StreamController<String> _onReceive = StreamController.broadcast(sync: true);
@@ -1560,7 +1558,7 @@
   Map<String, StreamController<Event>> _eventControllers = {};
 
   StreamController<Event> _getEventController(String eventName) {
-    StreamController<Event> controller = _eventControllers[eventName];
+    StreamController<Event>? controller = _eventControllers[eventName];
     if (controller == null) {
       controller = StreamController.broadcast();
       _eventControllers[eventName] = controller;
@@ -1568,14 +1566,14 @@
     return controller;
   }
 
-  DisposeHandler _disposeHandler;
+  late final DisposeHandler? _disposeHandler;
 
   VmService(
     Stream<dynamic> /*String|List<int>*/ inStream,
     void writeMessage(String message), {
-    Log log,
-    DisposeHandler disposeHandler,
-    Future streamClosed,
+    Log? log,
+    DisposeHandler? disposeHandler,
+    Future? streamClosed,
   }) {
     _streamSub = inStream.listen(_processMessage,
         onDone: () => _onDoneCompleter.complete());
@@ -1632,7 +1630,7 @@
     String isolateId,
     String scriptId,
     int line, {
-    int column,
+    int? column,
   }) =>
       _call('addBreakpoint', {
         'isolateId': isolateId,
@@ -1646,7 +1644,7 @@
     String isolateId,
     String scriptUri,
     int line, {
-    int column,
+    int? column,
   }) =>
       _call('addBreakpointWithScriptUri', {
         'isolateId': isolateId,
@@ -1674,7 +1672,7 @@
     String targetId,
     String selector,
     List<String> argumentIds, {
-    bool disableBreakpoints,
+    bool? disableBreakpoints,
   }) =>
       _call('invoke', {
         'isolateId': isolateId,
@@ -1690,8 +1688,8 @@
     String isolateId,
     String targetId,
     String expression, {
-    Map<String, String> scope,
-    bool disableBreakpoints,
+    Map<String, String>? scope,
+    bool? disableBreakpoints,
   }) =>
       _call('evaluate', {
         'isolateId': isolateId,
@@ -1707,8 +1705,8 @@
     String isolateId,
     int frameIndex,
     String expression, {
-    Map<String, String> scope,
-    bool disableBreakpoints,
+    Map<String, String>? scope,
+    bool? disableBreakpoints,
   }) =>
       _call('evaluateInFrame', {
         'isolateId': isolateId,
@@ -1721,7 +1719,7 @@
 
   @override
   Future<AllocationProfile> getAllocationProfile(String isolateId,
-          {bool reset, bool gc}) =>
+          {bool? reset, bool? gc}) =>
       _call('getAllocationProfile', {
         'isolateId': isolateId,
         if (reset != null && reset) 'reset': reset,
@@ -1780,8 +1778,8 @@
   Future<Obj> getObject(
     String isolateId,
     String objectId, {
-    int offset,
-    int count,
+    int? offset,
+    int? count,
   }) =>
       _call('getObject', {
         'isolateId': isolateId,
@@ -1805,7 +1803,7 @@
       _call('getProcessMemoryUsage');
 
   @override
-  Future<Stack> getStack(String isolateId, {int limit}) => _call('getStack', {
+  Future<Stack> getStack(String isolateId, {int? limit}) => _call('getStack', {
         'isolateId': isolateId,
         if (limit != null) 'limit': limit,
       });
@@ -1819,10 +1817,10 @@
     String isolateId,
     /*List<SourceReportKind>*/
     List<String> reports, {
-    String scriptId,
-    int tokenPos,
-    int endTokenPos,
-    bool forceCompile,
+    String? scriptId,
+    int? tokenPos,
+    int? endTokenPos,
+    bool? forceCompile,
   }) =>
       _call('getSourceReport', {
         'isolateId': isolateId,
@@ -1841,7 +1839,7 @@
 
   @override
   Future<Timeline> getVMTimeline(
-          {int timeOriginMicros, int timeExtentMicros}) =>
+          {int? timeOriginMicros, int? timeExtentMicros}) =>
       _call('getVMTimeline', {
         if (timeOriginMicros != null) 'timeOriginMicros': timeOriginMicros,
         if (timeExtentMicros != null) 'timeExtentMicros': timeExtentMicros,
@@ -1868,10 +1866,10 @@
   @override
   Future<ReloadReport> reloadSources(
     String isolateId, {
-    bool force,
-    bool pause,
-    String rootLibUri,
-    String packagesUri,
+    bool? force,
+    bool? pause,
+    String? rootLibUri,
+    String? packagesUri,
   }) =>
       _call('reloadSources', {
         'isolateId': isolateId,
@@ -1892,7 +1890,7 @@
 
   @override
   Future<Success> resume(String isolateId,
-          {/*StepOption*/ String step, int frameIndex}) =>
+          {/*StepOption*/ String? step, int? frameIndex}) =>
       _call('resume', {
         'isolateId': isolateId,
         if (step != null) 'step': step,
@@ -1938,7 +1936,8 @@
 
   /// Call an arbitrary service protocol method. This allows clients to call
   /// methods not explicitly exposed by this library.
-  Future<Response> callMethod(String method, {String isolateId, Map args}) {
+  Future<Response> callMethod(String method,
+      {String? isolateId, Map<String, dynamic>? args}) {
     return callServiceExtension(method, isolateId: isolateId, args: args);
   }
 
@@ -1947,11 +1946,11 @@
   /// See https://api.dart.dev/stable/dart-developer/dart-developer-library.html.
   @override
   Future<Response> callServiceExtension(String method,
-      {String isolateId, Map args}) {
+      {String? isolateId, Map<String, dynamic>? args}) {
     if (args == null && isolateId == null) {
       return _call(method);
     } else if (args == null) {
-      return _call(method, {'isolateId': isolateId});
+      return _call(method, {'isolateId': isolateId!});
     } else {
       args = Map.from(args);
       if (isolateId != null) {
@@ -1974,7 +1973,7 @@
     });
     _completers.clear();
     if (_disposeHandler != null) {
-      await _disposeHandler();
+      await _disposeHandler!();
     }
     if (!_onDoneCompleter.isCompleted) {
       _onDoneCompleter.complete();
@@ -2032,22 +2031,21 @@
         bytes.buffer, bytes.offsetInBytes + metaOffset, metaLength));
     final data = ByteData.view(
         bytes.buffer, bytes.offsetInBytes + dataOffset, dataLength);
-    dynamic map = jsonDecode(meta);
-    if (map != null && map['method'] == 'streamNotify') {
+    dynamic map = jsonDecode(meta)!;
+    if (map['method'] == 'streamNotify') {
       String streamId = map['params']['streamId'];
       Map event = map['params']['event'];
       event['data'] = data;
       _getEventController(streamId)
-          .add(createServiceObject(event, const ['Event']));
+          .add(createServiceObject(event, const ['Event'])! as Event);
     }
   }
 
   void _processMessageStr(String message) {
-    var json;
+    late Map<String, dynamic> json;
     try {
       _onReceive.add(message);
-
-      json = jsonDecode(message);
+      json = jsonDecode(message)!;
     } catch (e, s) {
       _log.severe('unable to decode message: ${message}, ${e}\n${s}');
       return;
@@ -2068,9 +2066,9 @@
   }
 
   void _processResponse(Map<String, dynamic> json) {
-    Completer completer = _completers.remove(json['id']);
-    String methodName = _methodCalls.remove(json['id']);
-    List<String> returnTypes = _methodReturnTypes[methodName];
+    Completer? completer = _completers.remove(json['id']);
+    String methodName = _methodCalls.remove(json['id'])!;
+    List<String> returnTypes = _methodReturnTypes[methodName] ?? [];
     if (completer == null) {
       _log.severe('unmatched request response: ${jsonEncode(json)}');
     } else if (json['error'] != null) {
@@ -2100,25 +2098,26 @@
 
   Future _processNotification(Map<String, dynamic> json) async {
     final String method = json['method'];
-    final Map params = json['params'] ?? <String, dynamic>{};
+    final Map<String, dynamic> params = json['params'] ?? <String, dynamic>{};
     if (method == 'streamNotify') {
       String streamId = params['streamId'];
       _getEventController(streamId)
-          .add(createServiceObject(params['event'], const ['Event']));
+          .add(createServiceObject(params['event'], const ['Event'])! as Event);
     } else {
       await _routeRequest(method, params);
     }
   }
 
   Future<Map> _routeRequest(String method, Map<String, dynamic> params) async {
-    if (!_services.containsKey(method)) {
+    final service = _services[method];
+    if (service == null) {
       RPCError error = RPCError(
           method, RPCError.kMethodNotFound, 'method not found \'$method\'');
       return {'error': error.toMap()};
     }
 
     try {
-      return await _services[method](params);
+      return await service(params);
     } catch (e, st) {
       RPCError error = RPCError.withDetails(
         method,
@@ -2153,22 +2152,22 @@
     return RPCError(callingMethod, json['code'], json['message'], json['data']);
   }
 
-  final String callingMethod;
+  final String? callingMethod;
   final int code;
   final String message;
-  final Map data;
+  final Map? data;
 
   RPCError(this.callingMethod, this.code, this.message, [this.data]);
 
   RPCError.withDetails(this.callingMethod, this.code, this.message,
-      {Object details})
+      {Object? details})
       : data = details == null ? null : <String, dynamic>{} {
     if (details != null) {
-      data['details'] = details;
+      data!['details'] = details;
     }
   }
 
-  String get details => data == null ? null : data['details'];
+  String? get details => data == null ? null : data!['details'];
 
   /// Return a map representation of this error suitable for converstion to
   /// json.
@@ -2198,17 +2197,17 @@
   final Sentinel sentinel;
 
   SentinelException.parse(this.callingMethod, Map<String, dynamic> data)
-      : sentinel = Sentinel.parse(data);
+      : sentinel = Sentinel.parse(data)!;
 
   String toString() => '$sentinel from ${callingMethod}()';
 }
 
 /// An `ExtensionData` is an arbitrary map that can have any contents.
 class ExtensionData {
-  static ExtensionData parse(Map json) =>
+  static ExtensionData? parse(Map<String, dynamic>? json) =>
       json == null ? null : ExtensionData._fromJson(json);
 
-  final Map data;
+  final Map<String, dynamic> data;
 
   ExtensionData() : data = {};
 
@@ -2535,30 +2534,30 @@
 // types
 
 class AllocationProfile extends Response {
-  static AllocationProfile parse(Map<String, dynamic> json) =>
+  static AllocationProfile? parse(Map<String, dynamic>? json) =>
       json == null ? null : AllocationProfile._fromJson(json);
 
   /// Allocation information for all class types.
-  List<ClassHeapStats> members;
+  late final List<ClassHeapStats> members;
 
   /// Information about memory usage for the isolate.
-  MemoryUsage memoryUsage;
+  late final MemoryUsage memoryUsage;
 
   /// The timestamp of the last accumulator reset.
   ///
   /// If the accumulators have not been reset, this field is not present.
   @optional
-  int dateLastAccumulatorReset;
+  late final int? dateLastAccumulatorReset;
 
   /// The timestamp of the last manually triggered GC.
   ///
   /// If a GC has not been triggered manually, this field is not present.
   @optional
-  int dateLastServiceGC;
+  late final int? dateLastServiceGC;
 
   AllocationProfile({
-    @required this.members,
-    @required this.memoryUsage,
+    required this.members,
+    required this.memoryUsage,
     this.dateLastAccumulatorReset,
     this.dateLastServiceGC,
   });
@@ -2566,9 +2565,12 @@
   AllocationProfile._fromJson(Map<String, dynamic> json)
       : super._fromJson(json) {
     members = List<ClassHeapStats>.from(
-        createServiceObject(json['members'], const ['ClassHeapStats']) ?? []);
+        createServiceObject(json['members'], const ['ClassHeapStats'])
+                as List? ??
+            []);
     memoryUsage =
-        createServiceObject(json['memoryUsage'], const ['MemoryUsage']);
+        createServiceObject(json['memoryUsage']!, const ['MemoryUsage'])
+            as MemoryUsage;
     dateLastAccumulatorReset = json['dateLastAccumulatorReset'] is String
         ? int.parse(json['dateLastAccumulatorReset'])
         : json['dateLastAccumulatorReset'];
@@ -2578,9 +2580,12 @@
   }
 
   @override
+  String get type => 'AllocationProfile';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'AllocationProfile';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'members': members.map((f) => f.toJson()).toList(),
       'memoryUsage': memoryUsage.toJson(),
@@ -2590,8 +2595,8 @@
     return json;
   }
 
-  String toString() => '[AllocationProfile ' //
-      'type: ${type}, members: ${members}, memoryUsage: ${memoryUsage}]';
+  String toString() =>
+      '[AllocationProfile members: ${members}, memoryUsage: ${memoryUsage}]';
 }
 
 /// A `BoundField` represents a field bound to a particular value in an
@@ -2603,27 +2608,28 @@
 /// If the field is being initialized, the `value` will be the
 /// `BeingInitialized` [Sentinel].
 class BoundField {
-  static BoundField parse(Map<String, dynamic> json) =>
+  static BoundField? parse(Map<String, dynamic>? json) =>
       json == null ? null : BoundField._fromJson(json);
 
-  FieldRef decl;
+  late final FieldRef decl;
 
   /// [value] can be one of [InstanceRef] or [Sentinel].
-  dynamic value;
+  late final dynamic value;
 
   BoundField({
-    @required this.decl,
-    @required this.value,
+    required this.decl,
+    required this.value,
   });
 
   BoundField._fromJson(Map<String, dynamic> json) {
-    decl = createServiceObject(json['decl'], const ['FieldRef']);
+    decl = createServiceObject(json['decl']!, const ['FieldRef']) as FieldRef;
     value =
-        createServiceObject(json['value'], const ['InstanceRef', 'Sentinel']);
+        createServiceObject(json['value']!, const ['InstanceRef', 'Sentinel'])
+            as dynamic;
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'decl': decl.toJson(),
       'value': value.toJson(),
@@ -2646,44 +2652,47 @@
 /// If the variable has been optimized out by the compiler, the `value` will be
 /// the `OptimizedOut` [Sentinel].
 class BoundVariable extends Response {
-  static BoundVariable parse(Map<String, dynamic> json) =>
+  static BoundVariable? parse(Map<String, dynamic>? json) =>
       json == null ? null : BoundVariable._fromJson(json);
 
-  String name;
+  late final String name;
 
   /// [value] can be one of [InstanceRef], [TypeArgumentsRef] or [Sentinel].
-  dynamic value;
+  late final dynamic value;
 
   /// The token position where this variable was declared.
-  int declarationTokenPos;
+  late final int declarationTokenPos;
 
   /// The first token position where this variable is visible to the scope.
-  int scopeStartTokenPos;
+  late final int scopeStartTokenPos;
 
   /// The last token position where this variable is visible to the scope.
-  int scopeEndTokenPos;
+  late final int scopeEndTokenPos;
 
   BoundVariable({
-    @required this.name,
-    @required this.value,
-    @required this.declarationTokenPos,
-    @required this.scopeStartTokenPos,
-    @required this.scopeEndTokenPos,
+    required this.name,
+    required this.value,
+    required this.declarationTokenPos,
+    required this.scopeStartTokenPos,
+    required this.scopeEndTokenPos,
   });
 
   BoundVariable._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
-    value = createServiceObject(
-        json['value'], const ['InstanceRef', 'TypeArgumentsRef', 'Sentinel']);
-    declarationTokenPos = json['declarationTokenPos'];
-    scopeStartTokenPos = json['scopeStartTokenPos'];
-    scopeEndTokenPos = json['scopeEndTokenPos'];
+    name = json['name'] ?? '';
+    value = createServiceObject(json['value']!,
+        const ['InstanceRef', 'TypeArgumentsRef', 'Sentinel']) as dynamic;
+    declarationTokenPos = json['declarationTokenPos'] ?? -1;
+    scopeStartTokenPos = json['scopeStartTokenPos'] ?? -1;
+    scopeEndTokenPos = json['scopeEndTokenPos'] ?? -1;
   }
 
   @override
+  String get type => 'BoundVariable';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'BoundVariable';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'name': name,
       'value': value.toJson(),
@@ -2695,7 +2704,7 @@
   }
 
   String toString() => '[BoundVariable ' //
-      'type: ${type}, name: ${name}, value: ${value}, declarationTokenPos: ${declarationTokenPos}, ' //
+      'name: ${name}, value: ${value}, declarationTokenPos: ${declarationTokenPos}, ' //
       'scopeStartTokenPos: ${scopeStartTokenPos}, scopeEndTokenPos: ${scopeEndTokenPos}]';
 }
 
@@ -2706,46 +2715,51 @@
 /// yet been compiled or in a library which has not been loaded (i.e. a deferred
 /// library).
 class Breakpoint extends Obj {
-  static Breakpoint parse(Map<String, dynamic> json) =>
+  static Breakpoint? parse(Map<String, dynamic>? json) =>
       json == null ? null : Breakpoint._fromJson(json);
 
   /// A number identifying this breakpoint to the user.
-  int breakpointNumber;
+  late final int breakpointNumber;
 
   /// Has this breakpoint been assigned to a specific program location?
-  bool resolved;
+  late final bool resolved;
 
   /// Is this a breakpoint that was added synthetically as part of a step
   /// OverAsyncSuspension resume command?
   @optional
-  bool isSyntheticAsyncContinuation;
+  late final bool? isSyntheticAsyncContinuation;
 
   /// SourceLocation when breakpoint is resolved, UnresolvedSourceLocation when
   /// a breakpoint is not resolved.
   ///
   /// [location] can be one of [SourceLocation] or [UnresolvedSourceLocation].
-  dynamic location;
+  late final dynamic location;
 
   Breakpoint({
-    @required this.breakpointNumber,
-    @required this.resolved,
-    @required this.location,
-    @required String id,
+    required this.breakpointNumber,
+    required this.resolved,
+    required this.location,
+    required String id,
     this.isSyntheticAsyncContinuation,
-  }) : super(id: id);
+  }) : super(
+          id: id,
+        );
 
   Breakpoint._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    breakpointNumber = json['breakpointNumber'];
-    resolved = json['resolved'];
+    breakpointNumber = json['breakpointNumber'] ?? -1;
+    resolved = json['resolved'] ?? false;
     isSyntheticAsyncContinuation = json['isSyntheticAsyncContinuation'];
-    location = createServiceObject(
-        json['location'], const ['SourceLocation', 'UnresolvedSourceLocation']);
+    location = createServiceObject(json['location']!,
+        const ['SourceLocation', 'UnresolvedSourceLocation']) as dynamic;
   }
 
   @override
+  String get type => 'Breakpoint';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Breakpoint';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'breakpointNumber': breakpointNumber,
       'resolved': resolved,
@@ -2761,31 +2775,36 @@
   operator ==(other) => other is Breakpoint && id == other.id;
 
   String toString() => '[Breakpoint ' //
-      'type: ${type}, id: ${id}, breakpointNumber: ${breakpointNumber}, ' //
-      'resolved: ${resolved}, location: ${location}]';
+      'id: ${id}, breakpointNumber: ${breakpointNumber}, resolved: ${resolved}, ' //
+      'location: ${location}]';
 }
 
 /// `ClassRef` is a reference to a `Class`.
 class ClassRef extends ObjRef {
-  static ClassRef parse(Map<String, dynamic> json) =>
+  static ClassRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : ClassRef._fromJson(json);
 
   /// The name of this class.
-  String name;
+  late final String name;
 
   ClassRef({
-    @required this.name,
-    @required String id,
-  }) : super(id: id);
+    required this.name,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   ClassRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
+    name = json['name'] ?? '';
   }
 
   @override
+  String get type => 'ClassRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@Class';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
     });
@@ -2796,106 +2815,120 @@
 
   operator ==(other) => other is ClassRef && id == other.id;
 
-  String toString() => '[ClassRef type: ${type}, id: ${id}, name: ${name}]';
+  String toString() => '[ClassRef id: ${id}, name: ${name}]';
 }
 
 /// A `Class` provides information about a Dart language class.
 class Class extends Obj implements ClassRef {
-  static Class parse(Map<String, dynamic> json) =>
+  static Class? parse(Map<String, dynamic>? json) =>
       json == null ? null : Class._fromJson(json);
 
   /// The name of this class.
-  String name;
+  late final String name;
 
   /// The error which occurred during class finalization, if it exists.
   @optional
-  ErrorRef error;
+  late final ErrorRef? error;
 
   /// Is this an abstract class?
-  bool isAbstract;
+  late final bool isAbstract;
 
   /// Is this a const class?
-  bool isConst;
+  late final bool isConst;
 
   /// The library which contains this class.
-  LibraryRef library;
+  late final LibraryRef library;
 
   /// The location of this class in the source code.
   @optional
-  SourceLocation location;
+  late final SourceLocation? location;
 
   /// The superclass of this class, if any.
   @optional
-  ClassRef superClass;
+  late final ClassRef? superClass;
 
   /// The supertype for this class, if any.
   ///
   /// The value will be of the kind: Type.
   @optional
-  InstanceRef superType;
+  late final InstanceRef? superType;
 
   /// A list of interface types for this class.
   ///
   /// The values will be of the kind: Type.
-  List<InstanceRef> interfaces;
+  late final List<InstanceRef> interfaces;
 
   /// The mixin type for this class, if any.
   ///
   /// The value will be of the kind: Type.
   @optional
-  InstanceRef mixin;
+  late final InstanceRef? mixin;
 
   /// A list of fields in this class. Does not include fields from superclasses.
-  List<FieldRef> fields;
+  late final List<FieldRef> fields;
 
   /// A list of functions in this class. Does not include functions from
   /// superclasses.
-  List<FuncRef> functions;
+  late final List<FuncRef> functions;
 
   /// A list of subclasses of this class.
-  List<ClassRef> subclasses;
+  late final List<ClassRef> subclasses;
 
   Class({
-    @required this.name,
-    @required this.isAbstract,
-    @required this.isConst,
-    @required this.library,
-    @required this.interfaces,
-    @required this.fields,
-    @required this.functions,
-    @required this.subclasses,
-    @required String id,
+    required this.name,
+    required this.isAbstract,
+    required this.isConst,
+    required this.library,
+    required this.interfaces,
+    required this.fields,
+    required this.functions,
+    required this.subclasses,
+    required String id,
     this.error,
     this.location,
     this.superClass,
     this.superType,
     this.mixin,
-  }) : super(id: id);
+  }) : super(
+          id: id,
+        );
 
   Class._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
-    error = createServiceObject(json['error'], const ['ErrorRef']);
-    isAbstract = json['abstract'];
-    isConst = json['const'];
-    library = createServiceObject(json['library'], const ['LibraryRef']);
-    location = createServiceObject(json['location'], const ['SourceLocation']);
-    superClass = createServiceObject(json['super'], const ['ClassRef']);
-    superType = createServiceObject(json['superType'], const ['InstanceRef']);
+    name = json['name'] ?? '';
+    error = createServiceObject(json['error'], const ['ErrorRef']) as ErrorRef?;
+    isAbstract = json['abstract'] ?? false;
+    isConst = json['const'] ?? false;
+    library = createServiceObject(json['library']!, const ['LibraryRef'])
+        as LibraryRef;
+    location = createServiceObject(json['location'], const ['SourceLocation'])
+        as SourceLocation?;
+    superClass =
+        createServiceObject(json['super'], const ['ClassRef']) as ClassRef?;
+    superType = createServiceObject(json['superType'], const ['InstanceRef'])
+        as InstanceRef?;
     interfaces = List<InstanceRef>.from(
-        createServiceObject(json['interfaces'], const ['InstanceRef']) ?? []);
-    mixin = createServiceObject(json['mixin'], const ['InstanceRef']);
+        createServiceObject(json['interfaces'], const ['InstanceRef'])
+                as List? ??
+            []);
+    mixin = createServiceObject(json['mixin'], const ['InstanceRef'])
+        as InstanceRef?;
     fields = List<FieldRef>.from(
-        createServiceObject(json['fields'], const ['FieldRef']) ?? []);
+        createServiceObject(json['fields'], const ['FieldRef']) as List? ?? []);
     functions = List<FuncRef>.from(
-        createServiceObject(json['functions'], const ['FuncRef']) ?? []);
+        createServiceObject(json['functions'], const ['FuncRef']) as List? ??
+            []);
     subclasses = List<ClassRef>.from(
-        createServiceObject(json['subclasses'], const ['ClassRef']) ?? []);
+        createServiceObject(json['subclasses'], const ['ClassRef']) as List? ??
+            []);
   }
 
   @override
+  String get type => 'Class';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Class';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
       'abstract': isAbstract,
@@ -2922,46 +2955,50 @@
 }
 
 class ClassHeapStats extends Response {
-  static ClassHeapStats parse(Map<String, dynamic> json) =>
+  static ClassHeapStats? parse(Map<String, dynamic>? json) =>
       json == null ? null : ClassHeapStats._fromJson(json);
 
   /// The class for which this memory information is associated.
-  ClassRef classRef;
+  late final ClassRef classRef;
 
   /// The number of bytes allocated for instances of class since the accumulator
   /// was last reset.
-  int accumulatedSize;
+  late final int accumulatedSize;
 
   /// The number of bytes currently allocated for instances of class.
-  int bytesCurrent;
+  late final int bytesCurrent;
 
   /// The number of instances of class which have been allocated since the
   /// accumulator was last reset.
-  int instancesAccumulated;
+  late final int instancesAccumulated;
 
   /// The number of instances of class which are currently alive.
-  int instancesCurrent;
+  late final int instancesCurrent;
 
   ClassHeapStats({
-    @required this.classRef,
-    @required this.accumulatedSize,
-    @required this.bytesCurrent,
-    @required this.instancesAccumulated,
-    @required this.instancesCurrent,
+    required this.classRef,
+    required this.accumulatedSize,
+    required this.bytesCurrent,
+    required this.instancesAccumulated,
+    required this.instancesCurrent,
   });
 
   ClassHeapStats._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    classRef = createServiceObject(json['class'], const ['ClassRef']);
-    accumulatedSize = json['accumulatedSize'];
-    bytesCurrent = json['bytesCurrent'];
-    instancesAccumulated = json['instancesAccumulated'];
-    instancesCurrent = json['instancesCurrent'];
+    classRef =
+        createServiceObject(json['class']!, const ['ClassRef']) as ClassRef;
+    accumulatedSize = json['accumulatedSize'] ?? -1;
+    bytesCurrent = json['bytesCurrent'] ?? -1;
+    instancesAccumulated = json['instancesAccumulated'] ?? -1;
+    instancesCurrent = json['instancesCurrent'] ?? -1;
   }
 
   @override
+  String get type => 'ClassHeapStats';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'ClassHeapStats';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'class': classRef.toJson(),
       'accumulatedSize': accumulatedSize,
@@ -2973,64 +3010,73 @@
   }
 
   String toString() => '[ClassHeapStats ' //
-      'type: ${type}, classRef: ${classRef}, accumulatedSize: ${accumulatedSize}, ' //
+      'classRef: ${classRef}, accumulatedSize: ${accumulatedSize}, ' //
       'bytesCurrent: ${bytesCurrent}, instancesAccumulated: ${instancesAccumulated}, instancesCurrent: ${instancesCurrent}]';
 }
 
 class ClassList extends Response {
-  static ClassList parse(Map<String, dynamic> json) =>
+  static ClassList? parse(Map<String, dynamic>? json) =>
       json == null ? null : ClassList._fromJson(json);
 
-  List<ClassRef> classes;
+  late final List<ClassRef> classes;
 
   ClassList({
-    @required this.classes,
+    required this.classes,
   });
 
   ClassList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
     classes = List<ClassRef>.from(
-        createServiceObject(json['classes'], const ['ClassRef']) ?? []);
+        createServiceObject(json['classes'], const ['ClassRef']) as List? ??
+            []);
   }
 
   @override
+  String get type => 'ClassList';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'ClassList';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'classes': classes.map((f) => f.toJson()).toList(),
     });
     return json;
   }
 
-  String toString() => '[ClassList type: ${type}, classes: ${classes}]';
+  String toString() => '[ClassList classes: ${classes}]';
 }
 
 /// `CodeRef` is a reference to a `Code` object.
 class CodeRef extends ObjRef {
-  static CodeRef parse(Map<String, dynamic> json) =>
+  static CodeRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : CodeRef._fromJson(json);
 
   /// A name for this code object.
-  String name;
+  late final String name;
 
   /// What kind of code object is this?
-  /*CodeKind*/ String kind;
+  late final /*CodeKind*/ String kind;
 
   CodeRef({
-    @required this.name,
-    @required this.kind,
-    @required String id,
-  }) : super(id: id);
+    required this.name,
+    required this.kind,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   CodeRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
-    kind = json['kind'];
+    name = json['name'] ?? '';
+    kind = json['kind'] ?? '';
   }
 
   @override
+  String get type => 'CodeRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@Code';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
       'kind': kind,
@@ -3042,36 +3088,40 @@
 
   operator ==(other) => other is CodeRef && id == other.id;
 
-  String toString() =>
-      '[CodeRef type: ${type}, id: ${id}, name: ${name}, kind: ${kind}]';
+  String toString() => '[CodeRef id: ${id}, name: ${name}, kind: ${kind}]';
 }
 
 /// A `Code` object represents compiled code in the Dart VM.
 class Code extends ObjRef implements CodeRef {
-  static Code parse(Map<String, dynamic> json) =>
+  static Code? parse(Map<String, dynamic>? json) =>
       json == null ? null : Code._fromJson(json);
 
   /// A name for this code object.
-  String name;
+  late final String name;
 
   /// What kind of code object is this?
-  /*CodeKind*/ String kind;
+  late final /*CodeKind*/ String kind;
 
   Code({
-    @required this.name,
-    @required this.kind,
-    @required String id,
-  }) : super(id: id);
+    required this.name,
+    required this.kind,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   Code._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
-    kind = json['kind'];
+    name = json['name'] ?? '';
+    kind = json['kind'] ?? '';
   }
 
   @override
+  String get type => 'Code';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Code';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
       'kind': kind,
@@ -3083,30 +3133,34 @@
 
   operator ==(other) => other is Code && id == other.id;
 
-  String toString() =>
-      '[Code type: ${type}, id: ${id}, name: ${name}, kind: ${kind}]';
+  String toString() => '[Code id: ${id}, name: ${name}, kind: ${kind}]';
 }
 
 class ContextRef extends ObjRef {
-  static ContextRef parse(Map<String, dynamic> json) =>
+  static ContextRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : ContextRef._fromJson(json);
 
   /// The number of variables in this context.
-  int length;
+  late final int length;
 
   ContextRef({
-    @required this.length,
-    @required String id,
-  }) : super(id: id);
+    required this.length,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   ContextRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    length = json['length'];
+    length = json['length'] ?? -1;
   }
 
   @override
+  String get type => 'ContextRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@Context';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'length': length,
     });
@@ -3117,44 +3171,50 @@
 
   operator ==(other) => other is ContextRef && id == other.id;
 
-  String toString() =>
-      '[ContextRef type: ${type}, id: ${id}, length: ${length}]';
+  String toString() => '[ContextRef id: ${id}, length: ${length}]';
 }
 
 /// A `Context` is a data structure which holds the captured variables for some
 /// closure.
 class Context extends Obj implements ContextRef {
-  static Context parse(Map<String, dynamic> json) =>
+  static Context? parse(Map<String, dynamic>? json) =>
       json == null ? null : Context._fromJson(json);
 
   /// The number of variables in this context.
-  int length;
+  late final int length;
 
   /// The enclosing context for this context.
   @optional
-  Context parent;
+  late final Context? parent;
 
   /// The variables in this context object.
-  List<ContextElement> variables;
+  late final List<ContextElement> variables;
 
   Context({
-    @required this.length,
-    @required this.variables,
-    @required String id,
+    required this.length,
+    required this.variables,
+    required String id,
     this.parent,
-  }) : super(id: id);
+  }) : super(
+          id: id,
+        );
 
   Context._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    length = json['length'];
-    parent = createServiceObject(json['parent'], const ['Context']);
+    length = json['length'] ?? -1;
+    parent = createServiceObject(json['parent'], const ['Context']) as Context?;
     variables = List<ContextElement>.from(
-        createServiceObject(json['variables'], const ['ContextElement']) ?? []);
+        createServiceObject(json['variables'], const ['ContextElement'])
+                as List? ??
+            []);
   }
 
   @override
+  String get type => 'Context';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Context';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'length': length,
       'variables': variables.map((f) => f.toJson()).toList(),
@@ -3167,28 +3227,29 @@
 
   operator ==(other) => other is Context && id == other.id;
 
-  String toString() => '[Context ' //
-      'type: ${type}, id: ${id}, length: ${length}, variables: ${variables}]';
+  String toString() =>
+      '[Context id: ${id}, length: ${length}, variables: ${variables}]';
 }
 
 class ContextElement {
-  static ContextElement parse(Map<String, dynamic> json) =>
+  static ContextElement? parse(Map<String, dynamic>? json) =>
       json == null ? null : ContextElement._fromJson(json);
 
   /// [value] can be one of [InstanceRef] or [Sentinel].
-  dynamic value;
+  late final dynamic value;
 
   ContextElement({
-    @required this.value,
+    required this.value,
   });
 
   ContextElement._fromJson(Map<String, dynamic> json) {
     value =
-        createServiceObject(json['value'], const ['InstanceRef', 'Sentinel']);
+        createServiceObject(json['value']!, const ['InstanceRef', 'Sentinel'])
+            as dynamic;
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'value': value.toJson(),
     });
@@ -3200,71 +3261,76 @@
 
 /// See [getCpuSamples] and [CpuSample].
 class CpuSamples extends Response {
-  static CpuSamples parse(Map<String, dynamic> json) =>
+  static CpuSamples? parse(Map<String, dynamic>? json) =>
       json == null ? null : CpuSamples._fromJson(json);
 
   /// The sampling rate for the profiler in microseconds.
-  int samplePeriod;
+  late final int samplePeriod;
 
   /// The maximum possible stack depth for samples.
-  int maxStackDepth;
+  late final int maxStackDepth;
 
   /// The number of samples returned.
-  int sampleCount;
+  late final int sampleCount;
 
   /// The timespan the set of returned samples covers, in microseconds.
-  int timeSpan;
+  late final int timeSpan;
 
   /// The start of the period of time in which the returned samples were
   /// collected.
-  int timeOriginMicros;
+  late final int timeOriginMicros;
 
   /// The duration of time covered by the returned samples.
-  int timeExtentMicros;
+  late final int timeExtentMicros;
 
   /// The process ID for the VM.
-  int pid;
+  late final int pid;
 
   /// A list of functions seen in the relevant samples. These references can be
   /// looked up using the indicies provided in a `CpuSample` `stack` to
   /// determine which function was on the stack.
-  List<ProfileFunction> functions;
+  late final List<ProfileFunction> functions;
 
   /// A list of samples collected in the range `[timeOriginMicros,
   /// timeOriginMicros + timeExtentMicros]`
-  List<CpuSample> samples;
+  late final List<CpuSample> samples;
 
   CpuSamples({
-    @required this.samplePeriod,
-    @required this.maxStackDepth,
-    @required this.sampleCount,
-    @required this.timeSpan,
-    @required this.timeOriginMicros,
-    @required this.timeExtentMicros,
-    @required this.pid,
-    @required this.functions,
-    @required this.samples,
+    required this.samplePeriod,
+    required this.maxStackDepth,
+    required this.sampleCount,
+    required this.timeSpan,
+    required this.timeOriginMicros,
+    required this.timeExtentMicros,
+    required this.pid,
+    required this.functions,
+    required this.samples,
   });
 
   CpuSamples._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    samplePeriod = json['samplePeriod'];
-    maxStackDepth = json['maxStackDepth'];
-    sampleCount = json['sampleCount'];
-    timeSpan = json['timeSpan'];
-    timeOriginMicros = json['timeOriginMicros'];
-    timeExtentMicros = json['timeExtentMicros'];
-    pid = json['pid'];
+    samplePeriod = json['samplePeriod'] ?? -1;
+    maxStackDepth = json['maxStackDepth'] ?? -1;
+    sampleCount = json['sampleCount'] ?? -1;
+    timeSpan = json['timeSpan'] ?? -1;
+    timeOriginMicros = json['timeOriginMicros'] ?? -1;
+    timeExtentMicros = json['timeExtentMicros'] ?? -1;
+    pid = json['pid'] ?? -1;
     functions = List<ProfileFunction>.from(
-        createServiceObject(json['functions'], const ['ProfileFunction']) ??
+        createServiceObject(json['functions'], const ['ProfileFunction'])
+                as List? ??
             []);
     samples = List<CpuSample>.from(
-        createServiceObject(json['samples'], const ['CpuSample']) ?? []);
+        createServiceObject(json['samples'], const ['CpuSample']) as List? ??
+            []);
   }
 
   @override
+  String get type => 'CpuSamples';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'CpuSamples';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'samplePeriod': samplePeriod,
       'maxStackDepth': maxStackDepth,
@@ -3284,30 +3350,30 @@
 
 /// See [getCpuSamples] and [CpuSamples].
 class CpuSample {
-  static CpuSample parse(Map<String, dynamic> json) =>
+  static CpuSample? parse(Map<String, dynamic>? json) =>
       json == null ? null : CpuSample._fromJson(json);
 
   /// The thread ID representing the thread on which this sample was collected.
-  int tid;
+  late final int tid;
 
   /// The time this sample was collected in microseconds.
-  int timestamp;
+  late final int timestamp;
 
   /// The name of VM tag set when this sample was collected. Omitted if the VM
   /// tag for the sample is not considered valid.
   @optional
-  String vmTag;
+  late final String? vmTag;
 
   /// The name of the User tag set when this sample was collected. Omitted if no
   /// User tag was set when this sample was collected.
   @optional
-  String userTag;
+  late final String? userTag;
 
   /// Provided and set to true if the sample's stack was truncated. This can
   /// happen if the stack is deeper than the `stackDepth` in the `CpuSamples`
   /// response.
   @optional
-  bool truncated;
+  late final bool? truncated;
 
   /// The call stack at the time this sample was collected. The stack is to be
   /// interpreted as top to bottom. Each element in this array is a key into the
@@ -3317,20 +3383,20 @@
   ///
   /// `functions[stack[0]] = @Function(bar())` `functions[stack[1]] =
   /// @Function(foo())` `functions[stack[2]] = @Function(main())`
-  List<int> stack;
+  late final List<int> stack;
 
   CpuSample({
-    @required this.tid,
-    @required this.timestamp,
-    @required this.stack,
+    required this.tid,
+    required this.timestamp,
+    required this.stack,
     this.vmTag,
     this.userTag,
     this.truncated,
   });
 
   CpuSample._fromJson(Map<String, dynamic> json) {
-    tid = json['tid'];
-    timestamp = json['timestamp'];
+    tid = json['tid'] ?? -1;
+    timestamp = json['timestamp'] ?? -1;
     vmTag = json['vmTag'];
     userTag = json['userTag'];
     truncated = json['truncated'];
@@ -3338,7 +3404,7 @@
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'tid': tid,
       'timestamp': timestamp,
@@ -3356,30 +3422,35 @@
 
 /// `ErrorRef` is a reference to an `Error`.
 class ErrorRef extends ObjRef {
-  static ErrorRef parse(Map<String, dynamic> json) =>
+  static ErrorRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : ErrorRef._fromJson(json);
 
   /// What kind of error is this?
-  /*ErrorKind*/ String kind;
+  late final /*ErrorKind*/ String kind;
 
   /// A description of the error.
-  String message;
+  late final String message;
 
   ErrorRef({
-    @required this.kind,
-    @required this.message,
-    @required String id,
-  }) : super(id: id);
+    required this.kind,
+    required this.message,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   ErrorRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    kind = json['kind'];
-    message = json['message'];
+    kind = json['kind'] ?? '';
+    message = json['message'] ?? '';
   }
 
   @override
+  String get type => 'ErrorRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@Error';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'kind': kind,
       'message': message,
@@ -3392,50 +3463,57 @@
   operator ==(other) => other is ErrorRef && id == other.id;
 
   String toString() =>
-      '[ErrorRef type: ${type}, id: ${id}, kind: ${kind}, message: ${message}]';
+      '[ErrorRef id: ${id}, kind: ${kind}, message: ${message}]';
 }
 
 /// An `Error` represents a Dart language level error. This is distinct from an
 /// [RPC error].
 class Error extends Obj implements ErrorRef {
-  static Error parse(Map<String, dynamic> json) =>
+  static Error? parse(Map<String, dynamic>? json) =>
       json == null ? null : Error._fromJson(json);
 
   /// What kind of error is this?
-  /*ErrorKind*/ String kind;
+  late final /*ErrorKind*/ String kind;
 
   /// A description of the error.
-  String message;
+  late final String message;
 
   /// If this error is due to an unhandled exception, this is the exception
   /// thrown.
   @optional
-  InstanceRef exception;
+  late final InstanceRef? exception;
 
   /// If this error is due to an unhandled exception, this is the stacktrace
   /// object.
   @optional
-  InstanceRef stacktrace;
+  late final InstanceRef? stacktrace;
 
   Error({
-    @required this.kind,
-    @required this.message,
-    @required String id,
+    required this.kind,
+    required this.message,
+    required String id,
     this.exception,
     this.stacktrace,
-  }) : super(id: id);
+  }) : super(
+          id: id,
+        );
 
   Error._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    kind = json['kind'];
-    message = json['message'];
-    exception = createServiceObject(json['exception'], const ['InstanceRef']);
-    stacktrace = createServiceObject(json['stacktrace'], const ['InstanceRef']);
+    kind = json['kind'] ?? '';
+    message = json['message'] ?? '';
+    exception = createServiceObject(json['exception'], const ['InstanceRef'])
+        as InstanceRef?;
+    stacktrace = createServiceObject(json['stacktrace'], const ['InstanceRef'])
+        as InstanceRef?;
   }
 
   @override
+  String get type => 'Error';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Error';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'kind': kind,
       'message': message,
@@ -3449,8 +3527,7 @@
 
   operator ==(other) => other is Error && id == other.id;
 
-  String toString() =>
-      '[Error type: ${type}, id: ${id}, kind: ${kind}, message: ${message}]';
+  String toString() => '[Error id: ${id}, kind: ${kind}, message: ${message}]';
 }
 
 /// An `Event` is an asynchronous notification from the VM. It is delivered only
@@ -3459,31 +3536,31 @@
 ///
 /// For more information, see [events].
 class Event extends Response {
-  static Event parse(Map<String, dynamic> json) =>
+  static Event? parse(Map<String, dynamic>? json) =>
       json == null ? null : Event._fromJson(json);
 
   /// What kind of event is this?
-  /*EventKind*/ String kind;
+  late final /*EventKind*/ String kind;
 
   /// The isolate with which this event is associated.
   ///
   /// This is provided for all event kinds except for:
   ///  - VMUpdate, VMFlagUpdate
   @optional
-  IsolateRef isolate;
+  late final IsolateRef? isolate;
 
   /// The vm with which this event is associated.
   ///
   /// This is provided for the event kind:
   ///  - VMUpdate, VMFlagUpdate
   @optional
-  VMRef vm;
+  late final VMRef? vm;
 
   /// The timestamp (in milliseconds since the epoch) associated with this
   /// event. For some isolate pause events, the timestamp is from when the
   /// isolate was paused. For other events, the timestamp is from when the event
   /// was created.
-  int timestamp;
+  late final int timestamp;
 
   /// The breakpoint which was added, removed, or resolved.
   ///
@@ -3493,7 +3570,7 @@
   ///  - BreakpointRemoved
   ///  - BreakpointResolved
   @optional
-  Breakpoint breakpoint;
+  late final Breakpoint? breakpoint;
 
   /// The list of breakpoints at which we are currently paused for a
   /// PauseBreakpoint event.
@@ -3507,7 +3584,7 @@
   /// This is provided for the event kinds:
   ///  - PauseBreakpoint
   @optional
-  List<Breakpoint> pauseBreakpoints;
+  late final List<Breakpoint>? pauseBreakpoints;
 
   /// The top stack frame associated with this event, if applicable.
   ///
@@ -3523,54 +3600,54 @@
   /// the initial resume event that is delivered when an isolate begins
   /// execution.
   @optional
-  Frame topFrame;
+  late final Frame? topFrame;
 
   /// The exception associated with this event, if this is a PauseException
   /// event.
   @optional
-  InstanceRef exception;
+  late final InstanceRef? exception;
 
   /// An array of bytes, encoded as a base64 string.
   ///
   /// This is provided for the WriteEvent event.
   @optional
-  String bytes;
+  late final String? bytes;
 
   /// The argument passed to dart:developer.inspect.
   ///
   /// This is provided for the Inspect event.
   @optional
-  InstanceRef inspectee;
+  late final InstanceRef? inspectee;
 
   /// The RPC name of the extension that was added.
   ///
   /// This is provided for the ServiceExtensionAdded event.
   @optional
-  String extensionRPC;
+  late final String? extensionRPC;
 
   /// The extension event kind.
   ///
   /// This is provided for the Extension event.
   @optional
-  String extensionKind;
+  late final String? extensionKind;
 
   /// The extension event data.
   ///
   /// This is provided for the Extension event.
   @optional
-  ExtensionData extensionData;
+  late final ExtensionData? extensionData;
 
   /// An array of TimelineEvents
   ///
   /// This is provided for the TimelineEvents event.
   @optional
-  List<TimelineEvent> timelineEvents;
+  late final List<TimelineEvent>? timelineEvents;
 
   /// The new set of recorded timeline streams.
   ///
   /// This is provided for the TimelineStreamSubscriptionsUpdate event.
   @optional
-  List<String> updatedStreams;
+  late final List<String>? updatedStreams;
 
   /// Is the isolate paused at an await, yield, or yield* statement?
   ///
@@ -3578,19 +3655,19 @@
   ///  - PauseBreakpoint
   ///  - PauseInterrupted
   @optional
-  bool atAsyncSuspension;
+  late final bool? atAsyncSuspension;
 
   /// The status (success or failure) related to the event. This is provided for
   /// the event kinds:
   ///  - IsolateReloaded
   @optional
-  String status;
+  late final String? status;
 
   /// LogRecord data.
   ///
   /// This is provided for the Logging event.
   @optional
-  LogRecord logRecord;
+  late final LogRecord? logRecord;
 
   /// The service identifier.
   ///
@@ -3598,7 +3675,7 @@
   ///  - ServiceRegistered
   ///  - ServiceUnregistered
   @optional
-  String service;
+  late final String? service;
 
   /// The RPC method that should be used to invoke the service.
   ///
@@ -3606,46 +3683,46 @@
   ///  - ServiceRegistered
   ///  - ServiceUnregistered
   @optional
-  String method;
+  late final String? method;
 
   /// The alias of the registered service.
   ///
   /// This is provided for the event kinds:
   ///  - ServiceRegistered
   @optional
-  String alias;
+  late final String? alias;
 
   /// The name of the changed flag.
   ///
   /// This is provided for the event kinds:
   ///  - VMFlagUpdate
   @optional
-  String flag;
+  late final String? flag;
 
   /// The new value of the changed flag.
   ///
   /// This is provided for the event kinds:
   ///  - VMFlagUpdate
   @optional
-  String newValue;
+  late final String? newValue;
 
   /// Specifies whether this event is the last of a group of events.
   ///
   /// This is provided for the event kinds:
   ///  - HeapSnapshot
   @optional
-  bool last;
+  late final bool? last;
 
   /// Binary data associated with the event.
   ///
   /// This is provided for the event kinds:
   ///   - HeapSnapshot
   @optional
-  ByteData data;
+  late final ByteData? data;
 
   Event({
-    @required this.kind,
-    @required this.timestamp,
+    required this.kind,
+    required this.timestamp,
     this.isolate,
     this.vm,
     this.breakpoint,
@@ -3672,32 +3749,38 @@
   });
 
   Event._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    kind = json['kind'];
-    isolate = createServiceObject(json['isolate'], const ['IsolateRef']);
-    vm = createServiceObject(json['vm'], const ['VMRef']);
-    timestamp = json['timestamp'];
-    breakpoint = createServiceObject(json['breakpoint'], const ['Breakpoint']);
+    kind = json['kind'] ?? '';
+    isolate = createServiceObject(json['isolate'], const ['IsolateRef'])
+        as IsolateRef?;
+    vm = createServiceObject(json['vm'], const ['VMRef']) as VMRef?;
+    timestamp = json['timestamp'] ?? -1;
+    breakpoint = createServiceObject(json['breakpoint'], const ['Breakpoint'])
+        as Breakpoint?;
     pauseBreakpoints = json['pauseBreakpoints'] == null
         ? null
-        : List<Breakpoint>.from(createServiceObject(
-            json['pauseBreakpoints'], const ['Breakpoint']));
-    topFrame = createServiceObject(json['topFrame'], const ['Frame']);
-    exception = createServiceObject(json['exception'], const ['InstanceRef']);
+        : List<Breakpoint>.from(
+            createServiceObject(json['pauseBreakpoints'], const ['Breakpoint'])!
+                as List);
+    topFrame = createServiceObject(json['topFrame'], const ['Frame']) as Frame?;
+    exception = createServiceObject(json['exception'], const ['InstanceRef'])
+        as InstanceRef?;
     bytes = json['bytes'];
-    inspectee = createServiceObject(json['inspectee'], const ['InstanceRef']);
+    inspectee = createServiceObject(json['inspectee'], const ['InstanceRef'])
+        as InstanceRef?;
     extensionRPC = json['extensionRPC'];
     extensionKind = json['extensionKind'];
     extensionData = ExtensionData.parse(json['extensionData']);
     timelineEvents = json['timelineEvents'] == null
         ? null
         : List<TimelineEvent>.from(createServiceObject(
-            json['timelineEvents'], const ['TimelineEvent']));
+            json['timelineEvents'], const ['TimelineEvent'])! as List);
     updatedStreams = json['updatedStreams'] == null
         ? null
         : List<String>.from(json['updatedStreams']);
     atAsyncSuspension = json['atAsyncSuspension'];
     status = json['status'];
-    logRecord = createServiceObject(json['logRecord'], const ['LogRecord']);
+    logRecord = createServiceObject(json['logRecord'], const ['LogRecord'])
+        as LogRecord?;
     service = json['service'];
     method = json['method'];
     alias = json['alias'];
@@ -3708,9 +3791,12 @@
   }
 
   @override
+  String get type => 'Event';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Event';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'kind': kind,
       'timestamp': timestamp,
@@ -3719,7 +3805,7 @@
     _setIfNotNull(json, 'vm', vm?.toJson());
     _setIfNotNull(json, 'breakpoint', breakpoint?.toJson());
     _setIfNotNull(json, 'pauseBreakpoints',
-        pauseBreakpoints?.map((f) => f?.toJson())?.toList());
+        pauseBreakpoints?.map((f) => f.toJson()).toList());
     _setIfNotNull(json, 'topFrame', topFrame?.toJson());
     _setIfNotNull(json, 'exception', exception?.toJson());
     _setIfNotNull(json, 'bytes', bytes);
@@ -3728,9 +3814,9 @@
     _setIfNotNull(json, 'extensionKind', extensionKind);
     _setIfNotNull(json, 'extensionData', extensionData?.data);
     _setIfNotNull(json, 'timelineEvents',
-        timelineEvents?.map((f) => f?.toJson())?.toList());
+        timelineEvents?.map((f) => f.toJson()).toList());
     _setIfNotNull(
-        json, 'updatedStreams', updatedStreams?.map((f) => f)?.toList());
+        json, 'updatedStreams', updatedStreams?.map((f) => f).toList());
     _setIfNotNull(json, 'atAsyncSuspension', atAsyncSuspension);
     _setIfNotNull(json, 'status', status);
     _setIfNotNull(json, 'logRecord', logRecord?.toJson());
@@ -3744,60 +3830,65 @@
     return json;
   }
 
-  String toString() =>
-      '[Event type: ${type}, kind: ${kind}, timestamp: ${timestamp}]';
+  String toString() => '[Event kind: ${kind}, timestamp: ${timestamp}]';
 }
 
 /// An `FieldRef` is a reference to a `Field`.
 class FieldRef extends ObjRef {
-  static FieldRef parse(Map<String, dynamic> json) =>
+  static FieldRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : FieldRef._fromJson(json);
 
   /// The name of this field.
-  String name;
+  late final String name;
 
   /// The owner of this field, which can be either a Library or a Class.
-  ObjRef owner;
+  late final ObjRef owner;
 
   /// The declared type of this field.
   ///
   /// The value will always be of one of the kinds: Type, TypeRef,
   /// TypeParameter, BoundedType.
-  InstanceRef declaredType;
+  late final InstanceRef declaredType;
 
   /// Is this field const?
-  bool isConst;
+  late final bool isConst;
 
   /// Is this field final?
-  bool isFinal;
+  late final bool isFinal;
 
   /// Is this field static?
-  bool isStatic;
+  late final bool isStatic;
 
   FieldRef({
-    @required this.name,
-    @required this.owner,
-    @required this.declaredType,
-    @required this.isConst,
-    @required this.isFinal,
-    @required this.isStatic,
-    @required String id,
-  }) : super(id: id);
+    required this.name,
+    required this.owner,
+    required this.declaredType,
+    required this.isConst,
+    required this.isFinal,
+    required this.isStatic,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   FieldRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
-    owner = createServiceObject(json['owner'], const ['ObjRef']);
+    name = json['name'] ?? '';
+    owner = createServiceObject(json['owner']!, const ['ObjRef']) as ObjRef;
     declaredType =
-        createServiceObject(json['declaredType'], const ['InstanceRef']);
-    isConst = json['const'];
-    isFinal = json['final'];
-    isStatic = json['static'];
+        createServiceObject(json['declaredType']!, const ['InstanceRef'])
+            as InstanceRef;
+    isConst = json['const'] ?? false;
+    isFinal = json['final'] ?? false;
+    isStatic = json['static'] ?? false;
   }
 
   @override
+  String get type => 'FieldRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@Field';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
       'owner': owner.toJson(),
@@ -3813,72 +3904,82 @@
 
   operator ==(other) => other is FieldRef && id == other.id;
 
-  String toString() => '[FieldRef]';
+  String toString() => '[FieldRef ' //
+      'id: ${id}, name: ${name}, owner: ${owner}, declaredType: ${declaredType}, ' //
+      'isConst: ${isConst}, isFinal: ${isFinal}, isStatic: ${isStatic}]';
 }
 
 /// A `Field` provides information about a Dart language field or variable.
 class Field extends Obj implements FieldRef {
-  static Field parse(Map<String, dynamic> json) =>
+  static Field? parse(Map<String, dynamic>? json) =>
       json == null ? null : Field._fromJson(json);
 
   /// The name of this field.
-  String name;
+  late final String name;
 
   /// The owner of this field, which can be either a Library or a Class.
-  ObjRef owner;
+  late final ObjRef owner;
 
   /// The declared type of this field.
   ///
   /// The value will always be of one of the kinds: Type, TypeRef,
   /// TypeParameter, BoundedType.
-  InstanceRef declaredType;
+  late final InstanceRef declaredType;
 
   /// Is this field const?
-  bool isConst;
+  late final bool isConst;
 
   /// Is this field final?
-  bool isFinal;
+  late final bool isFinal;
 
   /// Is this field static?
-  bool isStatic;
+  late final bool isStatic;
 
   /// The value of this field, if the field is static.
   @optional
-  InstanceRef staticValue;
+  late final InstanceRef? staticValue;
 
   /// The location of this field in the source code.
   @optional
-  SourceLocation location;
+  late final SourceLocation? location;
 
   Field({
-    @required this.name,
-    @required this.owner,
-    @required this.declaredType,
-    @required this.isConst,
-    @required this.isFinal,
-    @required this.isStatic,
-    @required String id,
+    required this.name,
+    required this.owner,
+    required this.declaredType,
+    required this.isConst,
+    required this.isFinal,
+    required this.isStatic,
+    required String id,
     this.staticValue,
     this.location,
-  }) : super(id: id);
+  }) : super(
+          id: id,
+        );
 
   Field._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
-    owner = createServiceObject(json['owner'], const ['ObjRef']);
+    name = json['name'] ?? '';
+    owner = createServiceObject(json['owner']!, const ['ObjRef']) as ObjRef;
     declaredType =
-        createServiceObject(json['declaredType'], const ['InstanceRef']);
-    isConst = json['const'];
-    isFinal = json['final'];
-    isStatic = json['static'];
+        createServiceObject(json['declaredType']!, const ['InstanceRef'])
+            as InstanceRef;
+    isConst = json['const'] ?? false;
+    isFinal = json['final'] ?? false;
+    isStatic = json['static'] ?? false;
     staticValue =
-        createServiceObject(json['staticValue'], const ['InstanceRef']);
-    location = createServiceObject(json['location'], const ['SourceLocation']);
+        createServiceObject(json['staticValue'], const ['InstanceRef'])
+            as InstanceRef?;
+    location = createServiceObject(json['location'], const ['SourceLocation'])
+        as SourceLocation?;
   }
 
   @override
+  String get type => 'Field';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Field';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
       'owner': owner.toJson(),
@@ -3896,45 +3997,47 @@
 
   operator ==(other) => other is Field && id == other.id;
 
-  String toString() => '[Field]';
+  String toString() => '[Field ' //
+      'id: ${id}, name: ${name}, owner: ${owner}, declaredType: ${declaredType}, ' //
+      'isConst: ${isConst}, isFinal: ${isFinal}, isStatic: ${isStatic}]';
 }
 
 /// A `Flag` represents a single VM command line flag.
 class Flag {
-  static Flag parse(Map<String, dynamic> json) =>
+  static Flag? parse(Map<String, dynamic>? json) =>
       json == null ? null : Flag._fromJson(json);
 
   /// The name of the flag.
-  String name;
+  late final String name;
 
   /// A description of the flag.
-  String comment;
+  late final String comment;
 
   /// Has this flag been modified from its default setting?
-  bool modified;
+  late final bool modified;
 
   /// The value of this flag as a string.
   ///
   /// If this property is absent, then the value of the flag was NULL.
   @optional
-  String valueAsString;
+  late final String? valueAsString;
 
   Flag({
-    @required this.name,
-    @required this.comment,
-    @required this.modified,
+    required this.name,
+    required this.comment,
+    required this.modified,
     this.valueAsString,
   });
 
   Flag._fromJson(Map<String, dynamic> json) {
-    name = json['name'];
-    comment = json['comment'];
-    modified = json['modified'];
+    name = json['name'] ?? '';
+    comment = json['comment'] ?? '';
+    modified = json['modified'] ?? false;
     valueAsString = json['valueAsString'];
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'name': name,
       'comment': comment,
@@ -3950,58 +4053,60 @@
 
 /// A `FlagList` represents the complete set of VM command line flags.
 class FlagList extends Response {
-  static FlagList parse(Map<String, dynamic> json) =>
+  static FlagList? parse(Map<String, dynamic>? json) =>
       json == null ? null : FlagList._fromJson(json);
 
   /// A list of all flags in the VM.
-  List<Flag> flags;
+  late final List<Flag> flags;
 
   FlagList({
-    @required this.flags,
+    required this.flags,
   });
 
   FlagList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
     flags = List<Flag>.from(
-        createServiceObject(json['flags'], const ['Flag']) ?? []);
+        createServiceObject(json['flags'], const ['Flag']) as List? ?? []);
   }
 
   @override
+  String get type => 'FlagList';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'FlagList';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'flags': flags.map((f) => f.toJson()).toList(),
     });
     return json;
   }
 
-  String toString() => '[FlagList type: ${type}, flags: ${flags}]';
+  String toString() => '[FlagList flags: ${flags}]';
 }
 
 class Frame extends Response {
-  static Frame parse(Map<String, dynamic> json) =>
+  static Frame? parse(Map<String, dynamic>? json) =>
       json == null ? null : Frame._fromJson(json);
 
-  int index;
+  late final int index;
 
   @optional
-  FuncRef function;
+  late final FuncRef? function;
 
   @optional
-  CodeRef code;
+  late final CodeRef? code;
 
   @optional
-  SourceLocation location;
+  late final SourceLocation? location;
 
   @optional
-  List<BoundVariable> vars;
+  late final List<BoundVariable>? vars;
 
   @optional
-  /*FrameKind*/
-  String kind;
+  late final /*FrameKind*/ String? kind;
 
   Frame({
-    @required this.index,
+    required this.index,
     this.function,
     this.code,
     this.location,
@@ -4010,74 +4115,85 @@
   });
 
   Frame._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    index = json['index'];
-    function = createServiceObject(json['function'], const ['FuncRef']);
-    code = createServiceObject(json['code'], const ['CodeRef']);
-    location = createServiceObject(json['location'], const ['SourceLocation']);
+    index = json['index'] ?? -1;
+    function =
+        createServiceObject(json['function'], const ['FuncRef']) as FuncRef?;
+    code = createServiceObject(json['code'], const ['CodeRef']) as CodeRef?;
+    location = createServiceObject(json['location'], const ['SourceLocation'])
+        as SourceLocation?;
     vars = json['vars'] == null
         ? null
         : List<BoundVariable>.from(
-            createServiceObject(json['vars'], const ['BoundVariable']));
+            createServiceObject(json['vars'], const ['BoundVariable'])!
+                as List);
     kind = json['kind'];
   }
 
   @override
+  String get type => 'Frame';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Frame';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'index': index,
     });
     _setIfNotNull(json, 'function', function?.toJson());
     _setIfNotNull(json, 'code', code?.toJson());
     _setIfNotNull(json, 'location', location?.toJson());
-    _setIfNotNull(json, 'vars', vars?.map((f) => f?.toJson())?.toList());
+    _setIfNotNull(json, 'vars', vars?.map((f) => f.toJson()).toList());
     _setIfNotNull(json, 'kind', kind);
     return json;
   }
 
-  String toString() => '[Frame type: ${type}, index: ${index}]';
+  String toString() => '[Frame index: ${index}]';
 }
 
 /// An `FuncRef` is a reference to a `Func`.
 class FuncRef extends ObjRef {
-  static FuncRef parse(Map<String, dynamic> json) =>
+  static FuncRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : FuncRef._fromJson(json);
 
   /// The name of this function.
-  String name;
+  late final String name;
 
   /// The owner of this function, which can be a Library, Class, or a Function.
   ///
   /// [owner] can be one of [LibraryRef], [ClassRef] or [FuncRef].
-  dynamic owner;
+  late final dynamic owner;
 
   /// Is this function static?
-  bool isStatic;
+  late final bool isStatic;
 
   /// Is this function const?
-  bool isConst;
+  late final bool isConst;
 
   FuncRef({
-    @required this.name,
-    @required this.owner,
-    @required this.isStatic,
-    @required this.isConst,
-    @required String id,
-  }) : super(id: id);
+    required this.name,
+    required this.owner,
+    required this.isStatic,
+    required this.isConst,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   FuncRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
+    name = json['name'] ?? '';
     owner = createServiceObject(
-        json['owner'], const ['LibraryRef', 'ClassRef', 'FuncRef']);
-    isStatic = json['static'];
-    isConst = json['const'];
+        json['owner']!, const ['LibraryRef', 'ClassRef', 'FuncRef']) as dynamic;
+    isStatic = json['static'] ?? false;
+    isConst = json['const'] ?? false;
   }
 
   @override
+  String get type => 'FuncRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@Function';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
       'owner': owner.toJson(),
@@ -4092,61 +4208,67 @@
   operator ==(other) => other is FuncRef && id == other.id;
 
   String toString() => '[FuncRef ' //
-      'type: ${type}, id: ${id}, name: ${name}, owner: ${owner}, ' //
-      'isStatic: ${isStatic}, isConst: ${isConst}]';
+      'id: ${id}, name: ${name}, owner: ${owner}, isStatic: ${isStatic}, ' //
+      'isConst: ${isConst}]';
 }
 
 /// A `Func` represents a Dart language function.
 class Func extends Obj implements FuncRef {
-  static Func parse(Map<String, dynamic> json) =>
+  static Func? parse(Map<String, dynamic>? json) =>
       json == null ? null : Func._fromJson(json);
 
   /// The name of this function.
-  String name;
+  late final String name;
 
   /// The owner of this function, which can be a Library, Class, or a Function.
   ///
   /// [owner] can be one of [LibraryRef], [ClassRef] or [FuncRef].
-  dynamic owner;
+  late final dynamic owner;
 
   /// Is this function static?
-  bool isStatic;
+  late final bool isStatic;
 
   /// Is this function const?
-  bool isConst;
+  late final bool isConst;
 
   /// The location of this function in the source code.
   @optional
-  SourceLocation location;
+  late final SourceLocation? location;
 
   /// The compiled code associated with this function.
   @optional
-  CodeRef code;
+  late final CodeRef? code;
 
   Func({
-    @required this.name,
-    @required this.owner,
-    @required this.isStatic,
-    @required this.isConst,
-    @required String id,
+    required this.name,
+    required this.owner,
+    required this.isStatic,
+    required this.isConst,
+    required String id,
     this.location,
     this.code,
-  }) : super(id: id);
+  }) : super(
+          id: id,
+        );
 
   Func._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
+    name = json['name'] ?? '';
     owner = createServiceObject(
-        json['owner'], const ['LibraryRef', 'ClassRef', 'FuncRef']);
-    isStatic = json['static'];
-    isConst = json['const'];
-    location = createServiceObject(json['location'], const ['SourceLocation']);
-    code = createServiceObject(json['code'], const ['CodeRef']);
+        json['owner']!, const ['LibraryRef', 'ClassRef', 'FuncRef']) as dynamic;
+    isStatic = json['static'] ?? false;
+    isConst = json['const'] ?? false;
+    location = createServiceObject(json['location'], const ['SourceLocation'])
+        as SourceLocation?;
+    code = createServiceObject(json['code'], const ['CodeRef']) as CodeRef?;
   }
 
   @override
+  String get type => 'Func';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Function';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
       'owner': owner.toJson(),
@@ -4163,20 +4285,20 @@
   operator ==(other) => other is Func && id == other.id;
 
   String toString() => '[Func ' //
-      'type: ${type}, id: ${id}, name: ${name}, owner: ${owner}, ' //
-      'isStatic: ${isStatic}, isConst: ${isConst}]';
+      'id: ${id}, name: ${name}, owner: ${owner}, isStatic: ${isStatic}, ' //
+      'isConst: ${isConst}]';
 }
 
 /// `InstanceRef` is a reference to an `Instance`.
 class InstanceRef extends ObjRef {
-  static InstanceRef parse(Map<String, dynamic> json) =>
+  static InstanceRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : InstanceRef._fromJson(json);
 
   /// What kind of instance is this?
-  /*InstanceKind*/ String kind;
+  late final /*InstanceKind*/ String kind;
 
   /// Instance references always include their class.
-  ClassRef classRef;
+  late final ClassRef classRef;
 
   /// The value of this instance as a string.
   ///
@@ -4191,14 +4313,14 @@
   ///  - Int32x4
   ///  - StackTrace
   @optional
-  String valueAsString;
+  late final String? valueAsString;
 
   /// The valueAsString for String references may be truncated. If so, this
   /// property is added with the value 'true'.
   ///
   /// New code should use 'length' and 'count' instead.
   @optional
-  bool valueAsStringIsTruncated;
+  late final bool? valueAsStringIsTruncated;
 
   /// The length of a List or the number of associations in a Map or the number
   /// of codeunits in a String.
@@ -4222,28 +4344,28 @@
   ///  - Float32x4List
   ///  - Float64x2List
   @optional
-  int length;
+  late final int? length;
 
   /// The name of a Type instance.
   ///
   /// Provided for instance kinds:
   ///  - Type
   @optional
-  String name;
+  late final String? name;
 
   /// The corresponding Class if this Type has a resolved typeClass.
   ///
   /// Provided for instance kinds:
   ///  - Type
   @optional
-  ClassRef typeClass;
+  late final ClassRef? typeClass;
 
   /// The parameterized class of a type parameter:
   ///
   /// Provided for instance kinds:
   ///  - TypeParameter
   @optional
-  ClassRef parameterizedClass;
+  late final ClassRef? parameterizedClass;
 
   /// The pattern of a RegExp instance.
   ///
@@ -4252,47 +4374,47 @@
   /// Provided for instance kinds:
   ///  - RegExp
   @optional
-  InstanceRef pattern;
+  late final InstanceRef? pattern;
 
   /// The function associated with a Closure instance.
   ///
   /// Provided for instance kinds:
   ///  - Closure
   @optional
-  FuncRef closureFunction;
+  late final FuncRef? closureFunction;
 
   /// The context associated with a Closure instance.
   ///
   /// Provided for instance kinds:
   ///  - Closure
   @optional
-  ContextRef closureContext;
+  late final ContextRef? closureContext;
 
   /// The port ID for a ReceivePort.
   ///
   /// Provided for instance kinds:
   ///  - ReceivePort
   @optional
-  int portId;
+  late final int? portId;
 
   /// The stack trace associated with the allocation of a ReceivePort.
   ///
   /// Provided for instance kinds:
   ///  - ReceivePort
   @optional
-  InstanceRef allocationLocation;
+  late final InstanceRef? allocationLocation;
 
   /// A name associated with a ReceivePort used for debugging purposes.
   ///
   /// Provided for instance kinds:
   ///  - ReceivePort
   @optional
-  String debugName;
+  late final String? debugName;
 
   InstanceRef({
-    @required this.kind,
-    @required this.classRef,
-    @required String id,
+    required this.kind,
+    required this.classRef,
+    required String id,
     this.valueAsString,
     this.valueAsStringIsTruncated,
     this.length,
@@ -4305,33 +4427,45 @@
     this.portId,
     this.allocationLocation,
     this.debugName,
-  }) : super(id: id);
+  }) : super(
+          id: id,
+        );
 
   InstanceRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    kind = json['kind'];
-    classRef = createServiceObject(json['class'], const ['ClassRef']);
+    kind = json['kind'] ?? '';
+    classRef =
+        createServiceObject(json['class']!, const ['ClassRef']) as ClassRef;
     valueAsString = json['valueAsString'];
     valueAsStringIsTruncated = json['valueAsStringIsTruncated'];
     length = json['length'];
     name = json['name'];
-    typeClass = createServiceObject(json['typeClass'], const ['ClassRef']);
+    typeClass =
+        createServiceObject(json['typeClass'], const ['ClassRef']) as ClassRef?;
     parameterizedClass =
-        createServiceObject(json['parameterizedClass'], const ['ClassRef']);
-    pattern = createServiceObject(json['pattern'], const ['InstanceRef']);
+        createServiceObject(json['parameterizedClass'], const ['ClassRef'])
+            as ClassRef?;
+    pattern = createServiceObject(json['pattern'], const ['InstanceRef'])
+        as InstanceRef?;
     closureFunction =
-        createServiceObject(json['closureFunction'], const ['FuncRef']);
+        createServiceObject(json['closureFunction'], const ['FuncRef'])
+            as FuncRef?;
     closureContext =
-        createServiceObject(json['closureContext'], const ['ContextRef']);
+        createServiceObject(json['closureContext'], const ['ContextRef'])
+            as ContextRef?;
     portId = json['portId'];
     allocationLocation =
-        createServiceObject(json['allocationLocation'], const ['InstanceRef']);
+        createServiceObject(json['allocationLocation'], const ['InstanceRef'])
+            as InstanceRef?;
     debugName = json['debugName'];
   }
 
   @override
+  String get type => 'InstanceRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@Instance';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'kind': kind,
       'class': classRef.toJson(),
@@ -4355,21 +4489,21 @@
 
   operator ==(other) => other is InstanceRef && id == other.id;
 
-  String toString() => '[InstanceRef ' //
-      'type: ${type}, id: ${id}, kind: ${kind}, classRef: ${classRef}]';
+  String toString() =>
+      '[InstanceRef id: ${id}, kind: ${kind}, classRef: ${classRef}]';
 }
 
 /// An `Instance` represents an instance of the Dart language class `Obj`.
 class Instance extends Obj implements InstanceRef {
-  static Instance parse(Map<String, dynamic> json) =>
+  static Instance? parse(Map<String, dynamic>? json) =>
       json == null ? null : Instance._fromJson(json);
 
   /// What kind of instance is this?
-  /*InstanceKind*/ String kind;
+  late final /*InstanceKind*/ String kind;
 
   /// Instance references always include their class.
   @override
-  ClassRef classRef;
+  covariant late final ClassRef classRef;
 
   /// The value of this instance as a string.
   ///
@@ -4380,14 +4514,14 @@
   ///  - String (value may be truncated)
   ///  - StackTrace
   @optional
-  String valueAsString;
+  late final String? valueAsString;
 
   /// The valueAsString for String references may be truncated. If so, this
   /// property is added with the value 'true'.
   ///
   /// New code should use 'length' and 'count' instead.
   @optional
-  bool valueAsStringIsTruncated;
+  late final bool? valueAsStringIsTruncated;
 
   /// The length of a List or the number of associations in a Map or the number
   /// of codeunits in a String.
@@ -4411,7 +4545,7 @@
   ///  - Float32x4List
   ///  - Float64x2List
   @optional
-  int length;
+  late final int? length;
 
   /// The index of the first element or association or codeunit returned. This
   /// is only provided when it is non-zero.
@@ -4435,7 +4569,7 @@
   ///  - Float32x4List
   ///  - Float64x2List
   @optional
-  int offset;
+  late final int? offset;
 
   /// The number of elements or associations or codeunits returned. This is only
   /// provided when it is less than length.
@@ -4459,46 +4593,46 @@
   ///  - Float32x4List
   ///  - Float64x2List
   @optional
-  int count;
+  late final int? count;
 
   /// The name of a Type instance.
   ///
   /// Provided for instance kinds:
   ///  - Type
   @optional
-  String name;
+  late final String? name;
 
   /// The corresponding Class if this Type is canonical.
   ///
   /// Provided for instance kinds:
   ///  - Type
   @optional
-  ClassRef typeClass;
+  late final ClassRef? typeClass;
 
   /// The parameterized class of a type parameter:
   ///
   /// Provided for instance kinds:
   ///  - TypeParameter
   @optional
-  ClassRef parameterizedClass;
+  late final ClassRef? parameterizedClass;
 
   /// The fields of this Instance.
   @optional
-  List<BoundField> fields;
+  late final List<BoundField>? fields;
 
   /// The elements of a List instance.
   ///
   /// Provided for instance kinds:
   ///  - List
   @optional
-  List<dynamic> elements;
+  late final List<dynamic>? elements;
 
   /// The elements of a Map instance.
   ///
   /// Provided for instance kinds:
   ///  - Map
   @optional
-  List<MapAssociation> associations;
+  late final List<MapAssociation>? associations;
 
   /// The bytes of a TypedData instance.
   ///
@@ -4520,77 +4654,77 @@
   ///  - Float32x4List
   ///  - Float64x2List
   @optional
-  String bytes;
+  late final String? bytes;
 
   /// The referent of a MirrorReference instance.
   ///
   /// Provided for instance kinds:
   ///  - MirrorReference
   @optional
-  InstanceRef mirrorReferent;
+  late final InstanceRef? mirrorReferent;
 
   /// The pattern of a RegExp instance.
   ///
   /// Provided for instance kinds:
   ///  - RegExp
   @optional
-  InstanceRef pattern;
+  late final InstanceRef? pattern;
 
   /// The function associated with a Closure instance.
   ///
   /// Provided for instance kinds:
   ///  - Closure
   @optional
-  FuncRef closureFunction;
+  late final FuncRef? closureFunction;
 
   /// The context associated with a Closure instance.
   ///
   /// Provided for instance kinds:
   ///  - Closure
   @optional
-  ContextRef closureContext;
+  late final ContextRef? closureContext;
 
   /// Whether this regular expression is case sensitive.
   ///
   /// Provided for instance kinds:
   ///  - RegExp
   @optional
-  bool isCaseSensitive;
+  late final bool? isCaseSensitive;
 
   /// Whether this regular expression matches multiple lines.
   ///
   /// Provided for instance kinds:
   ///  - RegExp
   @optional
-  bool isMultiLine;
+  late final bool? isMultiLine;
 
   /// The key for a WeakProperty instance.
   ///
   /// Provided for instance kinds:
   ///  - WeakProperty
   @optional
-  InstanceRef propertyKey;
+  late final InstanceRef? propertyKey;
 
   /// The key for a WeakProperty instance.
   ///
   /// Provided for instance kinds:
   ///  - WeakProperty
   @optional
-  InstanceRef propertyValue;
+  late final InstanceRef? propertyValue;
 
   /// The type arguments for this type.
   ///
   /// Provided for instance kinds:
   ///  - Type
   @optional
-  TypeArgumentsRef typeArguments;
+  late final TypeArgumentsRef? typeArguments;
 
   /// The index of a TypeParameter instance.
   ///
   /// Provided for instance kinds:
   ///  - TypeParameter
   @optional
-  int parameterIndex;
+  late final int? parameterIndex;
 
   /// The type bounded by a BoundedType instance - or - the referent of a
   /// TypeRef instance.
@@ -4602,7 +4736,7 @@
   ///  - BoundedType
   ///  - TypeRef
   @optional
-  InstanceRef targetType;
+  late final InstanceRef? targetType;
 
   /// The bound of a TypeParameter or BoundedType.
   ///
@@ -4613,33 +4747,33 @@
   ///  - BoundedType
   ///  - TypeParameter
   @optional
-  InstanceRef bound;
+  late final InstanceRef? bound;
 
   /// The port ID for a ReceivePort.
   ///
   /// Provided for instance kinds:
   ///  - ReceivePort
   @optional
-  int portId;
+  late final int? portId;
 
   /// The stack trace associated with the allocation of a ReceivePort.
   ///
   /// Provided for instance kinds:
   ///  - ReceivePort
   @optional
-  InstanceRef allocationLocation;
+  late final InstanceRef? allocationLocation;
 
   /// A name associated with a ReceivePort used for debugging purposes.
   ///
   /// Provided for instance kinds:
   ///  - ReceivePort
   @optional
-  String debugName;
+  late final String? debugName;
 
   Instance({
-    @required this.kind,
-    @required this.classRef,
-    @required String id,
+    required this.kind,
+    required this.classRef,
+    required String id,
     this.valueAsString,
     this.valueAsStringIsTruncated,
     this.length,
@@ -4667,61 +4801,38 @@
     this.portId,
     this.allocationLocation,
     this.debugName,
-  }) : super(id: id);
+  }) : super(
+          id: id,
+          classRef: classRef,
+        );
 
   Instance._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    kind = json['kind'];
-    classRef = createServiceObject(json['class'], const ['ClassRef']);
+    kind = json['kind'] ?? '';
     valueAsString = json['valueAsString'];
     valueAsStringIsTruncated = json['valueAsStringIsTruncated'];
     length = json['length'];
     offset = json['offset'];
     count = json['count'];
     name = json['name'];
-    typeClass = createServiceObject(json['typeClass'], const ['ClassRef']);
-    parameterizedClass =
-        createServiceObject(json['parameterizedClass'], const ['ClassRef']);
-    fields = json['fields'] == null
-        ? null
-        : List<BoundField>.from(
-            createServiceObject(json['fields'], const ['BoundField']));
-    elements = json['elements'] == null
-        ? null
-        : List<dynamic>.from(
-            createServiceObject(json['elements'], const ['dynamic']));
     associations = json['associations'] == null
         ? null
         : List<MapAssociation>.from(
             _createSpecificObject(json['associations'], MapAssociation.parse));
     bytes = json['bytes'];
-    mirrorReferent =
-        createServiceObject(json['mirrorReferent'], const ['InstanceRef']);
-    pattern = createServiceObject(json['pattern'], const ['InstanceRef']);
-    closureFunction =
-        createServiceObject(json['closureFunction'], const ['FuncRef']);
-    closureContext =
-        createServiceObject(json['closureContext'], const ['ContextRef']);
     isCaseSensitive = json['isCaseSensitive'];
     isMultiLine = json['isMultiLine'];
-    propertyKey =
-        createServiceObject(json['propertyKey'], const ['InstanceRef']);
-    propertyValue =
-        createServiceObject(json['propertyValue'], const ['InstanceRef']);
-    typeArguments =
-        createServiceObject(json['typeArguments'], const ['TypeArgumentsRef']);
     parameterIndex = json['parameterIndex'];
-    targetType = createServiceObject(json['targetType'], const ['InstanceRef']);
-    bound = createServiceObject(json['bound'], const ['InstanceRef']);
     portId = json['portId'];
-    allocationLocation =
-        createServiceObject(json['allocationLocation'], const ['InstanceRef']);
     debugName = json['debugName'];
   }
 
   @override
+  String get type => 'Instance';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Instance';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'kind': kind,
       'class': classRef.toJson(),
@@ -4734,11 +4845,10 @@
     _setIfNotNull(json, 'name', name);
     _setIfNotNull(json, 'typeClass', typeClass?.toJson());
     _setIfNotNull(json, 'parameterizedClass', parameterizedClass?.toJson());
-    _setIfNotNull(json, 'fields', fields?.map((f) => f?.toJson())?.toList());
+    _setIfNotNull(json, 'fields', fields?.map((f) => f.toJson()).toList());
+    _setIfNotNull(json, 'elements', elements?.map((f) => f.toJson()).toList());
     _setIfNotNull(
-        json, 'elements', elements?.map((f) => f?.toJson())?.toList());
-    _setIfNotNull(
-        json, 'associations', associations?.map((f) => f?.toJson())?.toList());
+        json, 'associations', associations?.map((f) => f.toJson()).toList());
     _setIfNotNull(json, 'bytes', bytes);
     _setIfNotNull(json, 'mirrorReferent', mirrorReferent?.toJson());
     _setIfNotNull(json, 'pattern', pattern?.toJson());
@@ -4762,46 +4872,49 @@
 
   operator ==(other) => other is Instance && id == other.id;
 
-  String toString() => '[Instance ' //
-      'type: ${type}, id: ${id}, kind: ${kind}, classRef: ${classRef}]';
+  String toString() =>
+      '[Instance id: ${id}, kind: ${kind}, classRef: ${classRef}]';
 }
 
 /// `IsolateRef` is a reference to an `Isolate` object.
 class IsolateRef extends Response {
-  static IsolateRef parse(Map<String, dynamic> json) =>
+  static IsolateRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : IsolateRef._fromJson(json);
 
   /// The id which is passed to the getIsolate RPC to load this isolate.
-  String id;
+  late final String id;
 
   /// A numeric id for this isolate, represented as a string. Unique.
-  String number;
+  late final String number;
 
   /// A name identifying this isolate. Not guaranteed to be unique.
-  String name;
+  late final String name;
 
   /// Specifies whether the isolate was spawned by the VM or embedder for
   /// internal use. If `false`, this isolate is likely running user code.
-  bool isSystemIsolate;
+  late final bool isSystemIsolate;
 
   IsolateRef({
-    @required this.id,
-    @required this.number,
-    @required this.name,
-    @required this.isSystemIsolate,
+    required this.id,
+    required this.number,
+    required this.name,
+    required this.isSystemIsolate,
   });
 
   IsolateRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    id = json['id'];
-    number = json['number'];
-    name = json['name'];
-    isSystemIsolate = json['isSystemIsolate'];
+    id = json['id'] ?? '';
+    number = json['number'] ?? '';
+    name = json['name'] ?? '';
+    isSystemIsolate = json['isSystemIsolate'] ?? false;
   }
 
   @override
+  String get type => 'IsolateRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = '@Isolate';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'id': id,
       'number': number,
@@ -4816,123 +4929,132 @@
   operator ==(other) => other is IsolateRef && id == other.id;
 
   String toString() => '[IsolateRef ' //
-      'type: ${type}, id: ${id}, number: ${number}, name: ${name}, ' //
-      'isSystemIsolate: ${isSystemIsolate}]';
+      'id: ${id}, number: ${number}, name: ${name}, isSystemIsolate: ${isSystemIsolate}]';
 }
 
 /// An `Isolate` object provides information about one isolate in the VM.
 class Isolate extends Response implements IsolateRef {
-  static Isolate parse(Map<String, dynamic> json) =>
+  static Isolate? parse(Map<String, dynamic>? json) =>
       json == null ? null : Isolate._fromJson(json);
 
   /// The id which is passed to the getIsolate RPC to reload this isolate.
-  String id;
+  late final String id;
 
   /// A numeric id for this isolate, represented as a string. Unique.
-  String number;
+  late final String number;
 
   /// A name identifying this isolate. Not guaranteed to be unique.
-  String name;
+  late final String name;
 
   /// Specifies whether the isolate was spawned by the VM or embedder for
   /// internal use. If `false`, this isolate is likely running user code.
-  bool isSystemIsolate;
+  late final bool isSystemIsolate;
 
   /// The list of isolate flags provided to this isolate. See Dart_IsolateFlags
   /// in dart_api.h for the list of accepted isolate flags.
-  List<IsolateFlag> isolateFlags;
+  late final List<IsolateFlag> isolateFlags;
 
   /// The time that the VM started in milliseconds since the epoch.
   ///
   /// Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
-  int startTime;
+  late final int startTime;
 
   /// Is the isolate in a runnable state?
-  bool runnable;
+  late final bool runnable;
 
   /// The number of live ports for this isolate.
-  int livePorts;
+  late final int livePorts;
 
   /// Will this isolate pause when exiting?
-  bool pauseOnExit;
+  late final bool pauseOnExit;
 
   /// The last pause event delivered to the isolate. If the isolate is running,
   /// this will be a resume event.
-  Event pauseEvent;
+  late final Event pauseEvent;
 
   /// The root library for this isolate.
   ///
   /// Guaranteed to be initialized when the IsolateRunnable event fires.
   @optional
-  LibraryRef rootLib;
+  late final LibraryRef? rootLib;
 
   /// A list of all libraries for this isolate.
   ///
   /// Guaranteed to be initialized when the IsolateRunnable event fires.
-  List<LibraryRef> libraries;
+  late final List<LibraryRef> libraries;
 
   /// A list of all breakpoints for this isolate.
-  List<Breakpoint> breakpoints;
+  late final List<Breakpoint> breakpoints;
 
   /// The error that is causing this isolate to exit, if applicable.
   @optional
-  Error error;
+  late final Error? error;
 
   /// The current pause on exception mode for this isolate.
-  /*ExceptionPauseMode*/ String exceptionPauseMode;
+  late final /*ExceptionPauseMode*/ String exceptionPauseMode;
 
   /// The list of service extension RPCs that are registered for this isolate,
   /// if any.
   @optional
-  List<String> extensionRPCs;
+  late final List<String>? extensionRPCs;
 
   Isolate({
-    @required this.id,
-    @required this.number,
-    @required this.name,
-    @required this.isSystemIsolate,
-    @required this.isolateFlags,
-    @required this.startTime,
-    @required this.runnable,
-    @required this.livePorts,
-    @required this.pauseOnExit,
-    @required this.pauseEvent,
-    @required this.libraries,
-    @required this.breakpoints,
-    @required this.exceptionPauseMode,
+    required this.id,
+    required this.number,
+    required this.name,
+    required this.isSystemIsolate,
+    required this.isolateFlags,
+    required this.startTime,
+    required this.runnable,
+    required this.livePorts,
+    required this.pauseOnExit,
+    required this.pauseEvent,
+    required this.libraries,
+    required this.breakpoints,
+    required this.exceptionPauseMode,
     this.rootLib,
     this.error,
     this.extensionRPCs,
   });
 
   Isolate._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    id = json['id'];
-    number = json['number'];
-    name = json['name'];
-    isSystemIsolate = json['isSystemIsolate'];
+    id = json['id'] ?? '';
+    number = json['number'] ?? '';
+    name = json['name'] ?? '';
+    isSystemIsolate = json['isSystemIsolate'] ?? false;
     isolateFlags = List<IsolateFlag>.from(
-        createServiceObject(json['isolateFlags'], const ['IsolateFlag']) ?? []);
-    startTime = json['startTime'];
-    runnable = json['runnable'];
-    livePorts = json['livePorts'];
-    pauseOnExit = json['pauseOnExit'];
-    pauseEvent = createServiceObject(json['pauseEvent'], const ['Event']);
-    rootLib = createServiceObject(json['rootLib'], const ['LibraryRef']);
+        createServiceObject(json['isolateFlags'], const ['IsolateFlag'])
+                as List? ??
+            []);
+    startTime = json['startTime'] ?? -1;
+    runnable = json['runnable'] ?? false;
+    livePorts = json['livePorts'] ?? -1;
+    pauseOnExit = json['pauseOnExit'] ?? false;
+    pauseEvent =
+        createServiceObject(json['pauseEvent']!, const ['Event']) as Event;
+    rootLib = createServiceObject(json['rootLib'], const ['LibraryRef'])
+        as LibraryRef?;
     libraries = List<LibraryRef>.from(
-        createServiceObject(json['libraries'], const ['LibraryRef']) ?? []);
+        createServiceObject(json['libraries'], const ['LibraryRef']) as List? ??
+            []);
     breakpoints = List<Breakpoint>.from(
-        createServiceObject(json['breakpoints'], const ['Breakpoint']) ?? []);
-    error = createServiceObject(json['error'], const ['Error']);
-    exceptionPauseMode = json['exceptionPauseMode'];
+        createServiceObject(json['breakpoints'], const ['Breakpoint'])
+                as List? ??
+            []);
+    error = createServiceObject(json['error'], const ['Error']) as Error?;
+    exceptionPauseMode = json['exceptionPauseMode'] ?? '';
     extensionRPCs = json['extensionRPCs'] == null
         ? null
         : List<String>.from(json['extensionRPCs']);
   }
 
   @override
+  String get type => 'Isolate';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Isolate';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'id': id,
       'number': number,
@@ -4950,8 +5072,7 @@
     });
     _setIfNotNull(json, 'rootLib', rootLib?.toJson());
     _setIfNotNull(json, 'error', error?.toJson());
-    _setIfNotNull(
-        json, 'extensionRPCs', extensionRPCs?.map((f) => f)?.toList());
+    _setIfNotNull(json, 'extensionRPCs', extensionRPCs?.map((f) => f).toList());
     return json;
   }
 
@@ -4964,27 +5085,27 @@
 
 /// Represents the value of a single isolate flag. See [Isolate].
 class IsolateFlag {
-  static IsolateFlag parse(Map<String, dynamic> json) =>
+  static IsolateFlag? parse(Map<String, dynamic>? json) =>
       json == null ? null : IsolateFlag._fromJson(json);
 
   /// The name of the flag.
-  String name;
+  late final String name;
 
   /// The value of this flag as a string.
-  String valueAsString;
+  late final String valueAsString;
 
   IsolateFlag({
-    @required this.name,
-    @required this.valueAsString,
+    required this.name,
+    required this.valueAsString,
   });
 
   IsolateFlag._fromJson(Map<String, dynamic> json) {
-    name = json['name'];
-    valueAsString = json['valueAsString'];
+    name = json['name'] ?? '';
+    valueAsString = json['valueAsString'] ?? '';
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'name': name,
       'valueAsString': valueAsString,
@@ -4998,41 +5119,44 @@
 
 /// `IsolateGroupRef` is a reference to an `IsolateGroup` object.
 class IsolateGroupRef extends Response {
-  static IsolateGroupRef parse(Map<String, dynamic> json) =>
+  static IsolateGroupRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : IsolateGroupRef._fromJson(json);
 
   /// The id which is passed to the getIsolateGroup RPC to load this isolate
   /// group.
-  String id;
+  late final String id;
 
   /// A numeric id for this isolate group, represented as a string. Unique.
-  String number;
+  late final String number;
 
   /// A name identifying this isolate group. Not guaranteed to be unique.
-  String name;
+  late final String name;
 
   /// Specifies whether the isolate group was spawned by the VM or embedder for
   /// internal use. If `false`, this isolate group is likely running user code.
-  bool isSystemIsolateGroup;
+  late final bool isSystemIsolateGroup;
 
   IsolateGroupRef({
-    @required this.id,
-    @required this.number,
-    @required this.name,
-    @required this.isSystemIsolateGroup,
+    required this.id,
+    required this.number,
+    required this.name,
+    required this.isSystemIsolateGroup,
   });
 
   IsolateGroupRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    id = json['id'];
-    number = json['number'];
-    name = json['name'];
-    isSystemIsolateGroup = json['isSystemIsolateGroup'];
+    id = json['id'] ?? '';
+    number = json['number'] ?? '';
+    name = json['name'] ?? '';
+    isSystemIsolateGroup = json['isSystemIsolateGroup'] ?? false;
   }
 
   @override
+  String get type => 'IsolateGroupRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = '@IsolateGroup';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'id': id,
       'number': number,
@@ -5047,52 +5171,55 @@
   operator ==(other) => other is IsolateGroupRef && id == other.id;
 
   String toString() => '[IsolateGroupRef ' //
-      'type: ${type}, id: ${id}, number: ${number}, name: ${name}, ' //
-      'isSystemIsolateGroup: ${isSystemIsolateGroup}]';
+      'id: ${id}, number: ${number}, name: ${name}, isSystemIsolateGroup: ${isSystemIsolateGroup}]';
 }
 
 /// An `Isolate` object provides information about one isolate in the VM.
 class IsolateGroup extends Response implements IsolateGroupRef {
-  static IsolateGroup parse(Map<String, dynamic> json) =>
+  static IsolateGroup? parse(Map<String, dynamic>? json) =>
       json == null ? null : IsolateGroup._fromJson(json);
 
   /// The id which is passed to the getIsolate RPC to reload this isolate.
-  String id;
+  late final String id;
 
   /// A numeric id for this isolate, represented as a string. Unique.
-  String number;
+  late final String number;
 
   /// A name identifying this isolate. Not guaranteed to be unique.
-  String name;
+  late final String name;
 
   /// Specifies whether the isolate group was spawned by the VM or embedder for
   /// internal use. If `false`, this isolate group is likely running user code.
-  bool isSystemIsolateGroup;
+  late final bool isSystemIsolateGroup;
 
   /// A list of all isolates in this isolate group.
-  List<IsolateRef> isolates;
+  late final List<IsolateRef> isolates;
 
   IsolateGroup({
-    @required this.id,
-    @required this.number,
-    @required this.name,
-    @required this.isSystemIsolateGroup,
-    @required this.isolates,
+    required this.id,
+    required this.number,
+    required this.name,
+    required this.isSystemIsolateGroup,
+    required this.isolates,
   });
 
   IsolateGroup._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    id = json['id'];
-    number = json['number'];
-    name = json['name'];
-    isSystemIsolateGroup = json['isSystemIsolateGroup'];
+    id = json['id'] ?? '';
+    number = json['number'] ?? '';
+    name = json['name'] ?? '';
+    isSystemIsolateGroup = json['isSystemIsolateGroup'] ?? false;
     isolates = List<IsolateRef>.from(
-        createServiceObject(json['isolates'], const ['IsolateRef']) ?? []);
+        createServiceObject(json['isolates'], const ['IsolateRef']) as List? ??
+            []);
   }
 
   @override
+  String get type => 'IsolateGroup';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'IsolateGroup';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'id': id,
       'number': number,
@@ -5108,75 +5235,79 @@
   operator ==(other) => other is IsolateGroup && id == other.id;
 
   String toString() => '[IsolateGroup ' //
-      'type: ${type}, id: ${id}, number: ${number}, name: ${name}, ' //
-      'isSystemIsolateGroup: ${isSystemIsolateGroup}, isolates: ${isolates}]';
+      'id: ${id}, number: ${number}, name: ${name}, isSystemIsolateGroup: ${isSystemIsolateGroup}, ' //
+      'isolates: ${isolates}]';
 }
 
 /// See [getInboundReferences].
 class InboundReferences extends Response {
-  static InboundReferences parse(Map<String, dynamic> json) =>
+  static InboundReferences? parse(Map<String, dynamic>? json) =>
       json == null ? null : InboundReferences._fromJson(json);
 
   /// An array of inbound references to an object.
-  List<InboundReference> references;
+  late final List<InboundReference> references;
 
   InboundReferences({
-    @required this.references,
+    required this.references,
   });
 
   InboundReferences._fromJson(Map<String, dynamic> json)
       : super._fromJson(json) {
     references = List<InboundReference>.from(
-        createServiceObject(json['references'], const ['InboundReference']) ??
+        createServiceObject(json['references'], const ['InboundReference'])
+                as List? ??
             []);
   }
 
   @override
+  String get type => 'InboundReferences';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'InboundReferences';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'references': references.map((f) => f.toJson()).toList(),
     });
     return json;
   }
 
-  String toString() =>
-      '[InboundReferences type: ${type}, references: ${references}]';
+  String toString() => '[InboundReferences references: ${references}]';
 }
 
 /// See [getInboundReferences].
 class InboundReference {
-  static InboundReference parse(Map<String, dynamic> json) =>
+  static InboundReference? parse(Map<String, dynamic>? json) =>
       json == null ? null : InboundReference._fromJson(json);
 
   /// The object holding the inbound reference.
-  ObjRef source;
+  late final ObjRef source;
 
   /// If source is a List, parentListIndex is the index of the inbound
   /// reference.
   @optional
-  int parentListIndex;
+  late final int? parentListIndex;
 
   /// If source is a field of an object, parentField is the field containing the
   /// inbound reference.
   @optional
-  FieldRef parentField;
+  late final FieldRef? parentField;
 
   InboundReference({
-    @required this.source,
+    required this.source,
     this.parentListIndex,
     this.parentField,
   });
 
   InboundReference._fromJson(Map<String, dynamic> json) {
-    source = createServiceObject(json['source'], const ['ObjRef']);
+    source = createServiceObject(json['source']!, const ['ObjRef']) as ObjRef;
     parentListIndex = json['parentListIndex'];
-    parentField = createServiceObject(json['parentField'], const ['FieldRef']);
+    parentField = createServiceObject(json['parentField'], const ['FieldRef'])
+        as FieldRef?;
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'source': source.toJson(),
     });
@@ -5190,30 +5321,34 @@
 
 /// See [getInstances].
 class InstanceSet extends Response {
-  static InstanceSet parse(Map<String, dynamic> json) =>
+  static InstanceSet? parse(Map<String, dynamic>? json) =>
       json == null ? null : InstanceSet._fromJson(json);
 
   /// The number of instances of the requested type currently allocated.
-  int totalCount;
+  late final int totalCount;
 
   /// An array of instances of the requested type.
-  List<ObjRef> instances;
+  late final List<ObjRef> instances;
 
   InstanceSet({
-    @required this.totalCount,
-    @required this.instances,
+    required this.totalCount,
+    required this.instances,
   });
 
   InstanceSet._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    totalCount = json['totalCount'];
+    totalCount = json['totalCount'] ?? -1;
     instances = List<ObjRef>.from(createServiceObject(
-        json['instances'] ?? json['samples'], const ['ObjRef']));
+            (json['instances'] ?? json['samples']!) as List, const ['ObjRef'])!
+        as List);
   }
 
   @override
+  String get type => 'InstanceSet';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'InstanceSet';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'totalCount': totalCount,
       'instances': instances.map((f) => f.toJson()).toList(),
@@ -5221,36 +5356,41 @@
     return json;
   }
 
-  String toString() => '[InstanceSet ' //
-      'type: ${type}, totalCount: ${totalCount}, instances: ${instances}]';
+  String toString() =>
+      '[InstanceSet totalCount: ${totalCount}, instances: ${instances}]';
 }
 
 /// `LibraryRef` is a reference to a `Library`.
 class LibraryRef extends ObjRef {
-  static LibraryRef parse(Map<String, dynamic> json) =>
+  static LibraryRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : LibraryRef._fromJson(json);
 
   /// The name of this library.
-  String name;
+  late final String name;
 
   /// The uri of this library.
-  String uri;
+  late final String uri;
 
   LibraryRef({
-    @required this.name,
-    @required this.uri,
-    @required String id,
-  }) : super(id: id);
+    required this.name,
+    required this.uri,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   LibraryRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
-    uri = json['uri'];
+    name = json['name'] ?? '';
+    uri = json['uri'] ?? '';
   }
 
   @override
+  String get type => 'LibraryRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@Library';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
       'uri': uri,
@@ -5262,73 +5402,81 @@
 
   operator ==(other) => other is LibraryRef && id == other.id;
 
-  String toString() =>
-      '[LibraryRef type: ${type}, id: ${id}, name: ${name}, uri: ${uri}]';
+  String toString() => '[LibraryRef id: ${id}, name: ${name}, uri: ${uri}]';
 }
 
 /// A `Library` provides information about a Dart language library.
 ///
 /// See [setLibraryDebuggable].
 class Library extends Obj implements LibraryRef {
-  static Library parse(Map<String, dynamic> json) =>
+  static Library? parse(Map<String, dynamic>? json) =>
       json == null ? null : Library._fromJson(json);
 
   /// The name of this library.
-  String name;
+  late final String name;
 
   /// The uri of this library.
-  String uri;
+  late final String uri;
 
   /// Is this library debuggable? Default true.
-  bool debuggable;
+  late final bool debuggable;
 
   /// A list of the imports for this library.
-  List<LibraryDependency> dependencies;
+  late final List<LibraryDependency> dependencies;
 
   /// A list of the scripts which constitute this library.
-  List<ScriptRef> scripts;
+  late final List<ScriptRef> scripts;
 
   /// A list of the top-level variables in this library.
-  List<FieldRef> variables;
+  late final List<FieldRef> variables;
 
   /// A list of the top-level functions in this library.
-  List<FuncRef> functions;
+  late final List<FuncRef> functions;
 
   /// A list of all classes in this library.
-  List<ClassRef> classes;
+  late final List<ClassRef> classes;
 
   Library({
-    @required this.name,
-    @required this.uri,
-    @required this.debuggable,
-    @required this.dependencies,
-    @required this.scripts,
-    @required this.variables,
-    @required this.functions,
-    @required this.classes,
-    @required String id,
-  }) : super(id: id);
+    required this.name,
+    required this.uri,
+    required this.debuggable,
+    required this.dependencies,
+    required this.scripts,
+    required this.variables,
+    required this.functions,
+    required this.classes,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   Library._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
-    uri = json['uri'];
-    debuggable = json['debuggable'];
+    name = json['name'] ?? '';
+    uri = json['uri'] ?? '';
+    debuggable = json['debuggable'] ?? false;
     dependencies = List<LibraryDependency>.from(
-        _createSpecificObject(json['dependencies'], LibraryDependency.parse));
+        _createSpecificObject(json['dependencies']!, LibraryDependency.parse));
     scripts = List<ScriptRef>.from(
-        createServiceObject(json['scripts'], const ['ScriptRef']) ?? []);
+        createServiceObject(json['scripts'], const ['ScriptRef']) as List? ??
+            []);
     variables = List<FieldRef>.from(
-        createServiceObject(json['variables'], const ['FieldRef']) ?? []);
+        createServiceObject(json['variables'], const ['FieldRef']) as List? ??
+            []);
     functions = List<FuncRef>.from(
-        createServiceObject(json['functions'], const ['FuncRef']) ?? []);
+        createServiceObject(json['functions'], const ['FuncRef']) as List? ??
+            []);
     classes = List<ClassRef>.from(
-        createServiceObject(json['classes'], const ['ClassRef']) ?? []);
+        createServiceObject(json['classes'], const ['ClassRef']) as List? ??
+            []);
   }
 
   @override
+  String get type => 'Library';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Library';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
       'uri': uri,
@@ -5351,37 +5499,38 @@
 
 /// A `LibraryDependency` provides information about an import or export.
 class LibraryDependency {
-  static LibraryDependency parse(Map<String, dynamic> json) =>
+  static LibraryDependency? parse(Map<String, dynamic>? json) =>
       json == null ? null : LibraryDependency._fromJson(json);
 
   /// Is this dependency an import (rather than an export)?
-  bool isImport;
+  late final bool isImport;
 
   /// Is this dependency deferred?
-  bool isDeferred;
+  late final bool isDeferred;
 
   /// The prefix of an 'as' import, or null.
-  String prefix;
+  late final String prefix;
 
   /// The library being imported or exported.
-  LibraryRef target;
+  late final LibraryRef target;
 
   LibraryDependency({
-    @required this.isImport,
-    @required this.isDeferred,
-    @required this.prefix,
-    @required this.target,
+    required this.isImport,
+    required this.isDeferred,
+    required this.prefix,
+    required this.target,
   });
 
   LibraryDependency._fromJson(Map<String, dynamic> json) {
-    isImport = json['isImport'];
-    isDeferred = json['isDeferred'];
-    prefix = json['prefix'];
-    target = createServiceObject(json['target'], const ['LibraryRef']);
+    isImport = json['isImport'] ?? false;
+    isDeferred = json['isDeferred'] ?? false;
+    prefix = json['prefix'] ?? '';
+    target = createServiceObject(json['target']!, const ['LibraryRef'])
+        as LibraryRef;
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'isImport': isImport,
       'isDeferred': isDeferred,
@@ -5397,62 +5546,70 @@
 }
 
 class LogRecord extends Response {
-  static LogRecord parse(Map<String, dynamic> json) =>
+  static LogRecord? parse(Map<String, dynamic>? json) =>
       json == null ? null : LogRecord._fromJson(json);
 
   /// The log message.
-  InstanceRef message;
+  late final InstanceRef message;
 
   /// The timestamp.
-  int time;
+  late final int time;
 
   /// The severity level (a value between 0 and 2000).
   ///
   /// See the package:logging `Level` class for an overview of the possible
   /// values.
-  int level;
+  late final int level;
 
   /// A monotonically increasing sequence number.
-  int sequenceNumber;
+  late final int sequenceNumber;
 
   /// The name of the source of the log message.
-  InstanceRef loggerName;
+  late final InstanceRef loggerName;
 
   /// The zone where the log was emitted.
-  InstanceRef zone;
+  late final InstanceRef zone;
 
   /// An error object associated with this log event.
-  InstanceRef error;
+  late final InstanceRef error;
 
   /// A stack trace associated with this log event.
-  InstanceRef stackTrace;
+  late final InstanceRef stackTrace;
 
   LogRecord({
-    @required this.message,
-    @required this.time,
-    @required this.level,
-    @required this.sequenceNumber,
-    @required this.loggerName,
-    @required this.zone,
-    @required this.error,
-    @required this.stackTrace,
+    required this.message,
+    required this.time,
+    required this.level,
+    required this.sequenceNumber,
+    required this.loggerName,
+    required this.zone,
+    required this.error,
+    required this.stackTrace,
   });
 
   LogRecord._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    message = createServiceObject(json['message'], const ['InstanceRef']);
-    time = json['time'];
-    level = json['level'];
-    sequenceNumber = json['sequenceNumber'];
-    loggerName = createServiceObject(json['loggerName'], const ['InstanceRef']);
-    zone = createServiceObject(json['zone'], const ['InstanceRef']);
-    error = createServiceObject(json['error'], const ['InstanceRef']);
-    stackTrace = createServiceObject(json['stackTrace'], const ['InstanceRef']);
+    message = createServiceObject(json['message']!, const ['InstanceRef'])
+        as InstanceRef;
+    time = json['time'] ?? -1;
+    level = json['level'] ?? -1;
+    sequenceNumber = json['sequenceNumber'] ?? -1;
+    loggerName = createServiceObject(json['loggerName']!, const ['InstanceRef'])
+        as InstanceRef;
+    zone = createServiceObject(json['zone']!, const ['InstanceRef'])
+        as InstanceRef;
+    error = createServiceObject(json['error']!, const ['InstanceRef'])
+        as InstanceRef;
+    stackTrace = createServiceObject(json['stackTrace']!, const ['InstanceRef'])
+        as InstanceRef;
   }
 
   @override
+  String get type => 'LogRecord';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'LogRecord';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'message': message.toJson(),
       'time': time,
@@ -5470,28 +5627,30 @@
 }
 
 class MapAssociation {
-  static MapAssociation parse(Map<String, dynamic> json) =>
+  static MapAssociation? parse(Map<String, dynamic>? json) =>
       json == null ? null : MapAssociation._fromJson(json);
 
   /// [key] can be one of [InstanceRef] or [Sentinel].
-  dynamic key;
+  late final dynamic key;
 
   /// [value] can be one of [InstanceRef] or [Sentinel].
-  dynamic value;
+  late final dynamic value;
 
   MapAssociation({
-    @required this.key,
-    @required this.value,
+    required this.key,
+    required this.value,
   });
 
   MapAssociation._fromJson(Map<String, dynamic> json) {
-    key = createServiceObject(json['key'], const ['InstanceRef', 'Sentinel']);
+    key = createServiceObject(json['key']!, const ['InstanceRef', 'Sentinel'])
+        as dynamic;
     value =
-        createServiceObject(json['value'], const ['InstanceRef', 'Sentinel']);
+        createServiceObject(json['value']!, const ['InstanceRef', 'Sentinel'])
+            as dynamic;
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'key': key.toJson(),
       'value': value.toJson(),
@@ -5505,7 +5664,7 @@
 /// A `MemoryUsage` object provides heap usage information for a specific
 /// isolate at a given point in time.
 class MemoryUsage extends Response {
-  static MemoryUsage parse(Map<String, dynamic> json) =>
+  static MemoryUsage? parse(Map<String, dynamic>? json) =>
       json == null ? null : MemoryUsage._fromJson(json);
 
   /// The amount of non-Dart memory that is retained by Dart objects. For
@@ -5515,32 +5674,35 @@
   /// supplied to these APIs from the VM embedder or native extensions. This
   /// external memory applies GC pressure, but is separate from heapUsage and
   /// heapCapacity.
-  int externalUsage;
+  late final int externalUsage;
 
   /// The total capacity of the heap in bytes. This is the amount of memory used
   /// by the Dart heap from the perspective of the operating system.
-  int heapCapacity;
+  late final int heapCapacity;
 
   /// The current heap memory usage in bytes. Heap usage is always less than or
   /// equal to the heap capacity.
-  int heapUsage;
+  late final int heapUsage;
 
   MemoryUsage({
-    @required this.externalUsage,
-    @required this.heapCapacity,
-    @required this.heapUsage,
+    required this.externalUsage,
+    required this.heapCapacity,
+    required this.heapUsage,
   });
 
   MemoryUsage._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    externalUsage = json['externalUsage'];
-    heapCapacity = json['heapCapacity'];
-    heapUsage = json['heapUsage'];
+    externalUsage = json['externalUsage'] ?? -1;
+    heapCapacity = json['heapCapacity'] ?? -1;
+    heapUsage = json['heapUsage'] ?? -1;
   }
 
   @override
+  String get type => 'MemoryUsage';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'MemoryUsage';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'externalUsage': externalUsage,
       'heapCapacity': heapCapacity,
@@ -5550,60 +5712,65 @@
   }
 
   String toString() => '[MemoryUsage ' //
-      'type: ${type}, externalUsage: ${externalUsage}, heapCapacity: ${heapCapacity}, ' //
+      'externalUsage: ${externalUsage}, heapCapacity: ${heapCapacity}, ' //
       'heapUsage: ${heapUsage}]';
 }
 
 /// A `Message` provides information about a pending isolate message and the
 /// function that will be invoked to handle it.
 class Message extends Response {
-  static Message parse(Map<String, dynamic> json) =>
+  static Message? parse(Map<String, dynamic>? json) =>
       json == null ? null : Message._fromJson(json);
 
   /// The index in the isolate's message queue. The 0th message being the next
   /// message to be processed.
-  int index;
+  late final int index;
 
   /// An advisory name describing this message.
-  String name;
+  late final String name;
 
   /// An instance id for the decoded message. This id can be passed to other
   /// RPCs, for example, getObject or evaluate.
-  String messageObjectId;
+  late final String messageObjectId;
 
   /// The size (bytes) of the encoded message.
-  int size;
+  late final int size;
 
   /// A reference to the function that will be invoked to handle this message.
   @optional
-  FuncRef handler;
+  late final FuncRef? handler;
 
   /// The source location of handler.
   @optional
-  SourceLocation location;
+  late final SourceLocation? location;
 
   Message({
-    @required this.index,
-    @required this.name,
-    @required this.messageObjectId,
-    @required this.size,
+    required this.index,
+    required this.name,
+    required this.messageObjectId,
+    required this.size,
     this.handler,
     this.location,
   });
 
   Message._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    index = json['index'];
-    name = json['name'];
-    messageObjectId = json['messageObjectId'];
-    size = json['size'];
-    handler = createServiceObject(json['handler'], const ['FuncRef']);
-    location = createServiceObject(json['location'], const ['SourceLocation']);
+    index = json['index'] ?? -1;
+    name = json['name'] ?? '';
+    messageObjectId = json['messageObjectId'] ?? '';
+    size = json['size'] ?? -1;
+    handler =
+        createServiceObject(json['handler'], const ['FuncRef']) as FuncRef?;
+    location = createServiceObject(json['location'], const ['SourceLocation'])
+        as SourceLocation?;
   }
 
   @override
+  String get type => 'Message';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Message';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'index': index,
       'name': name,
@@ -5616,29 +5783,29 @@
   }
 
   String toString() => '[Message ' //
-      'type: ${type}, index: ${index}, name: ${name}, messageObjectId: ${messageObjectId}, ' //
+      'index: ${index}, name: ${name}, messageObjectId: ${messageObjectId}, ' //
       'size: ${size}]';
 }
 
 /// A `NativeFunction` object is used to represent native functions in profiler
 /// samples. See [CpuSamples];
 class NativeFunction {
-  static NativeFunction parse(Map<String, dynamic> json) =>
+  static NativeFunction? parse(Map<String, dynamic>? json) =>
       json == null ? null : NativeFunction._fromJson(json);
 
   /// The name of the native function this object represents.
-  String name;
+  late final String name;
 
   NativeFunction({
-    @required this.name,
+    required this.name,
   });
 
   NativeFunction._fromJson(Map<String, dynamic> json) {
-    name = json['name'];
+    name = json['name'] ?? '';
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'name': name,
     });
@@ -5650,25 +5817,35 @@
 
 /// `NullValRef` is a reference to an a `NullVal`.
 class NullValRef extends InstanceRef {
-  static NullValRef parse(Map<String, dynamic> json) =>
+  static NullValRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : NullValRef._fromJson(json);
 
   /// Always 'null'.
   @override
-  String valueAsString;
+  covariant late final String valueAsString;
 
   NullValRef({
-    @required this.valueAsString,
-  });
+    required this.valueAsString,
+  }) : super(
+          id: 'instance/null',
+          kind: InstanceKind.kNull,
+          classRef: ClassRef(
+            id: 'class/null',
+            name: 'Null',
+          ),
+        );
 
   NullValRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    valueAsString = json['valueAsString'];
+    valueAsString = json['valueAsString'] ?? '';
   }
 
   @override
+  String get type => 'NullValRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@Null';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'valueAsString': valueAsString,
     });
@@ -5680,31 +5857,40 @@
   operator ==(other) => other is NullValRef && id == other.id;
 
   String toString() => '[NullValRef ' //
-      'type: ${type}, id: ${id}, kind: ${kind}, classRef: ${classRef}, ' //
-      'valueAsString: ${valueAsString}]';
+      'id: ${id}, kind: ${kind}, classRef: ${classRef}, valueAsString: ${valueAsString}]';
 }
 
 /// A `NullVal` object represents the Dart language value null.
 class NullVal extends Instance implements NullValRef {
-  static NullVal parse(Map<String, dynamic> json) =>
+  static NullVal? parse(Map<String, dynamic>? json) =>
       json == null ? null : NullVal._fromJson(json);
 
   /// Always 'null'.
   @override
-  String valueAsString;
+  covariant late final String valueAsString;
 
   NullVal({
-    @required this.valueAsString,
-  });
+    required this.valueAsString,
+  }) : super(
+          id: 'instance/null',
+          kind: InstanceKind.kNull,
+          classRef: ClassRef(
+            id: 'class/null',
+            name: 'Null',
+          ),
+        );
 
   NullVal._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    valueAsString = json['valueAsString'];
+    valueAsString = json['valueAsString'] ?? '';
   }
 
   @override
+  String get type => 'NullVal';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Null';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'valueAsString': valueAsString,
     });
@@ -5716,39 +5902,41 @@
   operator ==(other) => other is NullVal && id == other.id;
 
   String toString() => '[NullVal ' //
-      'type: ${type}, id: ${id}, kind: ${kind}, classRef: ${classRef}, ' //
-      'valueAsString: ${valueAsString}]';
+      'id: ${id}, kind: ${kind}, classRef: ${classRef}, valueAsString: ${valueAsString}]';
 }
 
 /// `ObjRef` is a reference to a `Obj`.
 class ObjRef extends Response {
-  static ObjRef parse(Map<String, dynamic> json) =>
+  static ObjRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : ObjRef._fromJson(json);
 
   /// A unique identifier for an Object. Passed to the getObject RPC to load
   /// this Object.
-  String id;
+  late final String id;
 
   /// Provided and set to true if the id of an Object is fixed. If true, the id
   /// of an Object is guaranteed not to change or expire. The object may,
   /// however, still be _Collected_.
   @optional
-  bool fixedId;
+  late final bool? fixedId;
 
   ObjRef({
-    @required this.id,
+    required this.id,
     this.fixedId,
   });
 
   ObjRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    id = json['id'];
+    id = json['id'] ?? '';
     fixedId = json['fixedId'];
   }
 
   @override
+  String get type => 'ObjRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = '@Object';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'id': id,
     });
@@ -5760,25 +5948,25 @@
 
   operator ==(other) => other is ObjRef && id == other.id;
 
-  String toString() => '[ObjRef type: ${type}, id: ${id}]';
+  String toString() => '[ObjRef id: ${id}]';
 }
 
 /// An `Obj` is a persistent object that is owned by some isolate.
 class Obj extends Response implements ObjRef {
-  static Obj parse(Map<String, dynamic> json) =>
+  static Obj? parse(Map<String, dynamic>? json) =>
       json == null ? null : Obj._fromJson(json);
 
   /// A unique identifier for an Object. Passed to the getObject RPC to reload
   /// this Object.
   ///
   /// Some objects may get a new id when they are reloaded.
-  String id;
+  late final String id;
 
   /// Provided and set to true if the id of an Object is fixed. If true, the id
   /// of an Object is guaranteed not to change or expire. The object may,
   /// however, still be _Collected_.
   @optional
-  bool fixedId;
+  late final bool? fixedId;
 
   /// If an object is allocated in the Dart heap, it will have a corresponding
   /// class object.
@@ -5789,7 +5977,7 @@
   /// Moving an Object into or out of the heap is considered a backwards
   /// compatible change for types other than Instance.
   @optional
-  ClassRef classRef;
+  late final ClassRef? classRef;
 
   /// The size of this object in the heap.
   ///
@@ -5799,26 +5987,30 @@
   /// implementation, this occurs for small integers, which are stored entirely
   /// within their object pointers.
   @optional
-  int size;
+  late final int? size;
 
   Obj({
-    @required this.id,
+    required this.id,
     this.fixedId,
     this.classRef,
     this.size,
   });
 
   Obj._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    id = json['id'];
+    id = json['id'] ?? '';
     fixedId = json['fixedId'];
-    classRef = createServiceObject(json['class'], const ['ClassRef']);
+    classRef =
+        createServiceObject(json['class'], const ['ClassRef']) as ClassRef?;
     size = json['size'];
   }
 
   @override
+  String get type => 'Obj';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Object';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'id': id,
     });
@@ -5832,38 +6024,42 @@
 
   operator ==(other) => other is Obj && id == other.id;
 
-  String toString() => '[Obj type: ${type}, id: ${id}]';
+  String toString() => '[Obj id: ${id}]';
 }
 
 /// A `PortList` contains a list of ports associated with some isolate.
 ///
 /// See [getPort].
 class PortList extends Response {
-  static PortList parse(Map<String, dynamic> json) =>
+  static PortList? parse(Map<String, dynamic>? json) =>
       json == null ? null : PortList._fromJson(json);
 
-  List<InstanceRef> ports;
+  late final List<InstanceRef> ports;
 
   PortList({
-    @required this.ports,
+    required this.ports,
   });
 
   PortList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
     ports = List<InstanceRef>.from(
-        createServiceObject(json['ports'], const ['InstanceRef']) ?? []);
+        createServiceObject(json['ports'], const ['InstanceRef']) as List? ??
+            []);
   }
 
   @override
+  String get type => 'PortList';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'PortList';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'ports': ports.map((f) => f.toJson()).toList(),
     });
     return json;
   }
 
-  String toString() => '[PortList type: ${type}, ports: ${ports}]';
+  String toString() => '[PortList ports: ${ports}]';
 }
 
 /// A `ProfileFunction` contains profiling information about a Dart or native
@@ -5871,43 +6067,44 @@
 ///
 /// See [CpuSamples].
 class ProfileFunction {
-  static ProfileFunction parse(Map<String, dynamic> json) =>
+  static ProfileFunction? parse(Map<String, dynamic>? json) =>
       json == null ? null : ProfileFunction._fromJson(json);
 
   /// The kind of function this object represents.
-  String kind;
+  late final String kind;
 
   /// The number of times function appeared on the stack during sampling events.
-  int inclusiveTicks;
+  late final int inclusiveTicks;
 
   /// The number of times function appeared on the top of the stack during
   /// sampling events.
-  int exclusiveTicks;
+  late final int exclusiveTicks;
 
   /// The resolved URL for the script containing function.
-  String resolvedUrl;
+  late final String resolvedUrl;
 
   /// The function captured during profiling.
-  dynamic function;
+  late final dynamic function;
 
   ProfileFunction({
-    @required this.kind,
-    @required this.inclusiveTicks,
-    @required this.exclusiveTicks,
-    @required this.resolvedUrl,
-    @required this.function,
+    required this.kind,
+    required this.inclusiveTicks,
+    required this.exclusiveTicks,
+    required this.resolvedUrl,
+    required this.function,
   });
 
   ProfileFunction._fromJson(Map<String, dynamic> json) {
-    kind = json['kind'];
-    inclusiveTicks = json['inclusiveTicks'];
-    exclusiveTicks = json['exclusiveTicks'];
-    resolvedUrl = json['resolvedUrl'];
-    function = createServiceObject(json['function'], const ['dynamic']);
+    kind = json['kind'] ?? '';
+    inclusiveTicks = json['inclusiveTicks'] ?? -1;
+    exclusiveTicks = json['exclusiveTicks'] ?? -1;
+    resolvedUrl = json['resolvedUrl'] ?? '';
+    function =
+        createServiceObject(json['function']!, const ['dynamic']) as dynamic;
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'kind': kind,
       'inclusiveTicks': inclusiveTicks,
@@ -5928,62 +6125,66 @@
 ///
 /// See [Protocol] and [getSupportedProtocols].
 class ProtocolList extends Response {
-  static ProtocolList parse(Map<String, dynamic> json) =>
+  static ProtocolList? parse(Map<String, dynamic>? json) =>
       json == null ? null : ProtocolList._fromJson(json);
 
   /// A list of supported protocols provided by this service.
-  List<Protocol> protocols;
+  late final List<Protocol> protocols;
 
   ProtocolList({
-    @required this.protocols,
+    required this.protocols,
   });
 
   ProtocolList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
     protocols = List<Protocol>.from(
-        createServiceObject(json['protocols'], const ['Protocol']) ?? []);
+        createServiceObject(json['protocols'], const ['Protocol']) as List? ??
+            []);
   }
 
   @override
+  String get type => 'ProtocolList';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'ProtocolList';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'protocols': protocols.map((f) => f.toJson()).toList(),
     });
     return json;
   }
 
-  String toString() => '[ProtocolList type: ${type}, protocols: ${protocols}]';
+  String toString() => '[ProtocolList protocols: ${protocols}]';
 }
 
 /// See [getSupportedProtocols].
 class Protocol {
-  static Protocol parse(Map<String, dynamic> json) =>
+  static Protocol? parse(Map<String, dynamic>? json) =>
       json == null ? null : Protocol._fromJson(json);
 
   /// The name of the supported protocol.
-  String protocolName;
+  late final String protocolName;
 
   /// The major revision of the protocol.
-  int major;
+  late final int major;
 
   /// The minor revision of the protocol.
-  int minor;
+  late final int minor;
 
   Protocol({
-    @required this.protocolName,
-    @required this.major,
-    @required this.minor,
+    required this.protocolName,
+    required this.major,
+    required this.minor,
   });
 
   Protocol._fromJson(Map<String, dynamic> json) {
-    protocolName = json['protocolName'];
-    major = json['major'];
-    minor = json['minor'];
+    protocolName = json['protocolName'] ?? '';
+    major = json['major'] ?? -1;
+    minor = json['minor'] ?? -1;
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'protocolName': protocolName,
       'major': major,
@@ -5998,68 +6199,73 @@
 
 /// Set [getProcessMemoryUsage].
 class ProcessMemoryUsage extends Response {
-  static ProcessMemoryUsage parse(Map<String, dynamic> json) =>
+  static ProcessMemoryUsage? parse(Map<String, dynamic>? json) =>
       json == null ? null : ProcessMemoryUsage._fromJson(json);
 
-  ProcessMemoryItem root;
+  late final ProcessMemoryItem root;
 
   ProcessMemoryUsage({
-    @required this.root,
+    required this.root,
   });
 
   ProcessMemoryUsage._fromJson(Map<String, dynamic> json)
       : super._fromJson(json) {
-    root = createServiceObject(json['root'], const ['ProcessMemoryItem']);
+    root = createServiceObject(json['root']!, const ['ProcessMemoryItem'])
+        as ProcessMemoryItem;
   }
 
   @override
+  String get type => 'ProcessMemoryUsage';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'ProcessMemoryUsage';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'root': root.toJson(),
     });
     return json;
   }
 
-  String toString() => '[ProcessMemoryUsage type: ${type}, root: ${root}]';
+  String toString() => '[ProcessMemoryUsage root: ${root}]';
 }
 
 class ProcessMemoryItem {
-  static ProcessMemoryItem parse(Map<String, dynamic> json) =>
+  static ProcessMemoryItem? parse(Map<String, dynamic>? json) =>
       json == null ? null : ProcessMemoryItem._fromJson(json);
 
   /// A short name for this bucket of memory.
-  String name;
+  late final String name;
 
   /// A longer description for this item.
-  String description;
+  late final String description;
 
   /// The amount of memory in bytes. This is a retained size, not a shallow
   /// size. That is, it includes the size of children.
-  int size;
+  late final int size;
 
   /// Subdivisons of this bucket of memory.
-  List<ProcessMemoryItem> children;
+  late final List<ProcessMemoryItem> children;
 
   ProcessMemoryItem({
-    @required this.name,
-    @required this.description,
-    @required this.size,
-    @required this.children,
+    required this.name,
+    required this.description,
+    required this.size,
+    required this.children,
   });
 
   ProcessMemoryItem._fromJson(Map<String, dynamic> json) {
-    name = json['name'];
-    description = json['description'];
-    size = json['size'];
+    name = json['name'] ?? '';
+    description = json['description'] ?? '';
+    size = json['size'] ?? -1;
     children = List<ProcessMemoryItem>.from(
-        createServiceObject(json['children'], const ['ProcessMemoryItem']) ??
+        createServiceObject(json['children'], const ['ProcessMemoryItem'])
+                as List? ??
             []);
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'name': name,
       'description': description,
@@ -6075,69 +6281,73 @@
 }
 
 class ReloadReport extends Response {
-  static ReloadReport parse(Map<String, dynamic> json) =>
+  static ReloadReport? parse(Map<String, dynamic>? json) =>
       json == null ? null : ReloadReport._fromJson(json);
 
   /// Did the reload succeed or fail?
-  bool success;
+  late final bool success;
 
   ReloadReport({
-    @required this.success,
+    required this.success,
   });
 
   ReloadReport._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    success = json['success'];
+    success = json['success'] ?? false;
   }
 
   @override
+  String get type => 'ReloadReport';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'ReloadReport';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'success': success,
     });
     return json;
   }
 
-  String toString() => '[ReloadReport type: ${type}, success: ${success}]';
+  String toString() => '[ReloadReport success: ${success}]';
 }
 
 /// See [RetainingPath].
 class RetainingObject {
-  static RetainingObject parse(Map<String, dynamic> json) =>
+  static RetainingObject? parse(Map<String, dynamic>? json) =>
       json == null ? null : RetainingObject._fromJson(json);
 
   /// An object that is part of a retaining path.
-  ObjRef value;
+  late final ObjRef value;
 
   /// The offset of the retaining object in a containing list.
   @optional
-  int parentListIndex;
+  late final int? parentListIndex;
 
   /// The key mapping to the retaining object in a containing map.
   @optional
-  ObjRef parentMapKey;
+  late final ObjRef? parentMapKey;
 
   /// The name of the field containing the retaining object within an object.
   @optional
-  String parentField;
+  late final String? parentField;
 
   RetainingObject({
-    @required this.value,
+    required this.value,
     this.parentListIndex,
     this.parentMapKey,
     this.parentField,
   });
 
   RetainingObject._fromJson(Map<String, dynamic> json) {
-    value = createServiceObject(json['value'], const ['ObjRef']);
+    value = createServiceObject(json['value']!, const ['ObjRef']) as ObjRef;
     parentListIndex = json['parentListIndex'];
-    parentMapKey = createServiceObject(json['parentMapKey'], const ['ObjRef']);
+    parentMapKey =
+        createServiceObject(json['parentMapKey'], const ['ObjRef']) as ObjRef?;
     parentField = json['parentField'];
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'value': value.toJson(),
     });
@@ -6152,37 +6362,42 @@
 
 /// See [getRetainingPath].
 class RetainingPath extends Response {
-  static RetainingPath parse(Map<String, dynamic> json) =>
+  static RetainingPath? parse(Map<String, dynamic>? json) =>
       json == null ? null : RetainingPath._fromJson(json);
 
   /// The length of the retaining path.
-  int length;
+  late final int length;
 
   /// The type of GC root which is holding a reference to the specified object.
   /// Possible values include:  * class table  * local handle  * persistent
   /// handle  * stack  * user global  * weak persistent handle  * unknown
-  String gcRootType;
+  late final String gcRootType;
 
   /// The chain of objects which make up the retaining path.
-  List<RetainingObject> elements;
+  late final List<RetainingObject> elements;
 
   RetainingPath({
-    @required this.length,
-    @required this.gcRootType,
-    @required this.elements,
+    required this.length,
+    required this.gcRootType,
+    required this.elements,
   });
 
   RetainingPath._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    length = json['length'];
-    gcRootType = json['gcRootType'];
+    length = json['length'] ?? -1;
+    gcRootType = json['gcRootType'] ?? '';
     elements = List<RetainingObject>.from(
-        createServiceObject(json['elements'], const ['RetainingObject']) ?? []);
+        createServiceObject(json['elements'], const ['RetainingObject'])
+                as List? ??
+            []);
   }
 
   @override
+  String get type => 'RetainingPath';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'RetainingPath';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'length': length,
       'gcRootType': gcRootType,
@@ -6192,38 +6407,34 @@
   }
 
   String toString() => '[RetainingPath ' //
-      'type: ${type}, length: ${length}, gcRootType: ${gcRootType}, ' //
-      'elements: ${elements}]';
+      'length: ${length}, gcRootType: ${gcRootType}, elements: ${elements}]';
 }
 
 /// Every non-error response returned by the Service Protocol extends
 /// `Response`. By using the `type` property, the client can determine which
 /// [type] of response has been provided.
 class Response {
-  static Response parse(Map<String, dynamic> json) =>
+  static Response? parse(Map<String, dynamic>? json) =>
       json == null ? null : Response._fromJson(json);
 
-  Map<String, dynamic> json;
+  Map<String, dynamic>? json;
 
-  /// Every response returned by the VM Service has the type property. This
-  /// allows the client distinguish between different kinds of responses.
-  String type;
+  Response();
 
-  Response({
-    @required this.type,
-  });
+  Response._fromJson(this.json);
 
-  Response._fromJson(this.json) {
-    type = json['type'];
-  }
+  String get type => 'Response';
 
   Map<String, dynamic> toJson() {
-    var result = json == null ? <String, dynamic>{} : Map.of(json);
-    result['type'] = type ?? 'Response';
+    final localJson = json;
+    final result = localJson == null
+        ? <String, dynamic>{}
+        : Map<String, dynamic>.of(localJson);
+    result['type'] = type;
     return result;
   }
 
-  String toString() => '[Response type: ${type}]';
+  String toString() => '[Response]';
 }
 
 /// A `Sentinel` is used to indicate that the normal response is not available.
@@ -6231,29 +6442,32 @@
 /// We use a `Sentinel` instead of an [error] for these cases because they do
 /// not represent a problematic condition. They are normal.
 class Sentinel extends Response {
-  static Sentinel parse(Map<String, dynamic> json) =>
+  static Sentinel? parse(Map<String, dynamic>? json) =>
       json == null ? null : Sentinel._fromJson(json);
 
   /// What kind of sentinel is this?
-  /*SentinelKind*/ String kind;
+  late final /*SentinelKind*/ String kind;
 
   /// A reasonable string representation of this sentinel.
-  String valueAsString;
+  late final String valueAsString;
 
   Sentinel({
-    @required this.kind,
-    @required this.valueAsString,
+    required this.kind,
+    required this.valueAsString,
   });
 
   Sentinel._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    kind = json['kind'];
-    valueAsString = json['valueAsString'];
+    kind = json['kind'] ?? '';
+    valueAsString = json['valueAsString'] ?? '';
   }
 
   @override
+  String get type => 'Sentinel';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Sentinel';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'kind': kind,
       'valueAsString': valueAsString,
@@ -6261,31 +6475,36 @@
     return json;
   }
 
-  String toString() => '[Sentinel ' //
-      'type: ${type}, kind: ${kind}, valueAsString: ${valueAsString}]';
+  String toString() =>
+      '[Sentinel kind: ${kind}, valueAsString: ${valueAsString}]';
 }
 
 /// `ScriptRef` is a reference to a `Script`.
 class ScriptRef extends ObjRef {
-  static ScriptRef parse(Map<String, dynamic> json) =>
+  static ScriptRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : ScriptRef._fromJson(json);
 
   /// The uri from which this script was loaded.
-  String uri;
+  late final String uri;
 
   ScriptRef({
-    @required this.uri,
-    @required String id,
-  }) : super(id: id);
+    required this.uri,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   ScriptRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    uri = json['uri'];
+    uri = json['uri'] ?? '';
   }
 
   @override
+  String get type => 'ScriptRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@Script';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'uri': uri,
     });
@@ -6296,7 +6515,7 @@
 
   operator ==(other) => other is ScriptRef && id == other.id;
 
-  String toString() => '[ScriptRef type: ${type}, id: ${id}, uri: ${uri}]';
+  String toString() => '[ScriptRef id: ${id}, uri: ${uri}]';
 }
 
 /// A `Script` provides information about a Dart language script.
@@ -6330,71 +6549,75 @@
 /// 101 | 1 | 8
 /// 102 | 2 | 7
 class Script extends Obj implements ScriptRef {
-  static Script parse(Map<String, dynamic> json) =>
+  static Script? parse(Map<String, dynamic>? json) =>
       json == null ? null : Script._fromJson(json);
 
   final _tokenToLine = <int, int>{};
   final _tokenToColumn = <int, int>{};
 
   /// The uri from which this script was loaded.
-  String uri;
+  late final String uri;
 
   /// The library which owns this script.
-  LibraryRef library;
+  late final LibraryRef library;
 
   @optional
-  int lineOffset;
+  late final int? lineOffset;
 
   @optional
-  int columnOffset;
+  late final int? columnOffset;
 
   /// The source code for this script. This can be null for certain built-in
   /// scripts.
   @optional
-  String source;
+  late final String? source;
 
   /// A table encoding a mapping from token position to line and column. This
   /// field is null if sources aren't available.
   @optional
-  List<List<int>> tokenPosTable;
+  late final List<List<int>>? tokenPosTable;
 
   Script({
-    @required this.uri,
-    @required this.library,
-    @required String id,
+    required this.uri,
+    required this.library,
+    required String id,
     this.lineOffset,
     this.columnOffset,
     this.source,
     this.tokenPosTable,
-  }) : super(id: id);
+  }) : super(
+          id: id,
+        );
 
   Script._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    uri = json['uri'];
-    library = createServiceObject(json['library'], const ['LibraryRef']);
+    uri = json['uri'] ?? '';
+    library = createServiceObject(json['library']!, const ['LibraryRef'])
+        as LibraryRef;
     lineOffset = json['lineOffset'];
     columnOffset = json['columnOffset'];
     source = json['source'];
     tokenPosTable = json['tokenPosTable'] == null
         ? null
         : List<List<int>>.from(
-            json['tokenPosTable'].map((dynamic list) => List<int>.from(list)));
+            json['tokenPosTable']!.map((dynamic list) => List<int>.from(list)));
     _parseTokenPosTable();
   }
 
   /// This function maps a token position to a line number.
   /// The VM considers the first line to be line 1.
-  int getLineNumberFromTokenPos(int tokenPos) => _tokenToLine[tokenPos];
+  int? getLineNumberFromTokenPos(int tokenPos) => _tokenToLine[tokenPos];
 
   /// This function maps a token position to a column number.
   /// The VM considers the first column to be column 1.
-  int getColumnNumberFromTokenPos(int tokenPos) => _tokenToColumn[tokenPos];
+  int? getColumnNumberFromTokenPos(int tokenPos) => _tokenToColumn[tokenPos];
 
   void _parseTokenPosTable() {
-    if (tokenPosTable == null) {
+    final tokenPositionTable = tokenPosTable;
+    if (tokenPositionTable == null) {
       return;
     }
-    final lineSet = Set<int>();
-    for (List line in tokenPosTable) {
+    final lineSet = <int>{};
+    for (List line in tokenPositionTable) {
       // Each entry begins with a line number...
       int lineNumber = line[0];
       lineSet.add(lineNumber);
@@ -6409,9 +6632,12 @@
   }
 
   @override
+  String get type => 'Script';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'Script';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'uri': uri,
       'library': library.toJson(),
@@ -6419,8 +6645,8 @@
     _setIfNotNull(json, 'lineOffset', lineOffset);
     _setIfNotNull(json, 'columnOffset', columnOffset);
     _setIfNotNull(json, 'source', source);
-    _setIfNotNull(json, 'tokenPosTable',
-        tokenPosTable?.map((f) => f?.toList())?.toList());
+    _setIfNotNull(
+        json, 'tokenPosTable', tokenPosTable?.map((f) => f.toList()).toList());
     return json;
   }
 
@@ -6428,70 +6654,77 @@
 
   operator ==(other) => other is Script && id == other.id;
 
-  String toString() =>
-      '[Script type: ${type}, id: ${id}, uri: ${uri}, library: ${library}]';
+  String toString() => '[Script id: ${id}, uri: ${uri}, library: ${library}]';
 }
 
 class ScriptList extends Response {
-  static ScriptList parse(Map<String, dynamic> json) =>
+  static ScriptList? parse(Map<String, dynamic>? json) =>
       json == null ? null : ScriptList._fromJson(json);
 
-  List<ScriptRef> scripts;
+  late final List<ScriptRef> scripts;
 
   ScriptList({
-    @required this.scripts,
+    required this.scripts,
   });
 
   ScriptList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
     scripts = List<ScriptRef>.from(
-        createServiceObject(json['scripts'], const ['ScriptRef']) ?? []);
+        createServiceObject(json['scripts'], const ['ScriptRef']) as List? ??
+            []);
   }
 
   @override
+  String get type => 'ScriptList';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'ScriptList';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'scripts': scripts.map((f) => f.toJson()).toList(),
     });
     return json;
   }
 
-  String toString() => '[ScriptList type: ${type}, scripts: ${scripts}]';
+  String toString() => '[ScriptList scripts: ${scripts}]';
 }
 
 /// The `SourceLocation` class is used to designate a position or range in some
 /// script.
 class SourceLocation extends Response {
-  static SourceLocation parse(Map<String, dynamic> json) =>
+  static SourceLocation? parse(Map<String, dynamic>? json) =>
       json == null ? null : SourceLocation._fromJson(json);
 
   /// The script containing the source location.
-  ScriptRef script;
+  late final ScriptRef script;
 
   /// The first token of the location.
-  int tokenPos;
+  late final int tokenPos;
 
   /// The last token of the location if this is a range.
   @optional
-  int endTokenPos;
+  late final int? endTokenPos;
 
   SourceLocation({
-    @required this.script,
-    @required this.tokenPos,
+    required this.script,
+    required this.tokenPos,
     this.endTokenPos,
   });
 
   SourceLocation._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    script = createServiceObject(json['script'], const ['ScriptRef']);
-    tokenPos = json['tokenPos'];
+    script =
+        createServiceObject(json['script']!, const ['ScriptRef']) as ScriptRef;
+    tokenPos = json['tokenPos'] ?? -1;
     endTokenPos = json['endTokenPos'];
   }
 
   @override
+  String get type => 'SourceLocation';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'SourceLocation';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'script': script.toJson(),
       'tokenPos': tokenPos,
@@ -6501,13 +6734,13 @@
   }
 
   String toString() =>
-      '[SourceLocation type: ${type}, script: ${script}, tokenPos: ${tokenPos}]';
+      '[SourceLocation script: ${script}, tokenPos: ${tokenPos}]';
 }
 
 /// The `SourceReport` class represents a set of reports tied to source
 /// locations in an isolate.
 class SourceReport extends Response {
-  static SourceReport parse(Map<String, dynamic> json) =>
+  static SourceReport? parse(Map<String, dynamic>? json) =>
       json == null ? null : SourceReport._fromJson(json);
 
   /// A list of ranges in the program source.  These ranges correspond to ranges
@@ -6518,27 +6751,31 @@
   /// functions.
   ///
   /// Note that ranges may be duplicated, in the case of mixins.
-  List<SourceReportRange> ranges;
+  late final List<SourceReportRange> ranges;
 
   /// A list of scripts, referenced by index in the report's ranges.
-  List<ScriptRef> scripts;
+  late final List<ScriptRef> scripts;
 
   SourceReport({
-    @required this.ranges,
-    @required this.scripts,
+    required this.ranges,
+    required this.scripts,
   });
 
   SourceReport._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
     ranges = List<SourceReportRange>.from(
-        _createSpecificObject(json['ranges'], SourceReportRange.parse));
+        _createSpecificObject(json['ranges']!, SourceReportRange.parse));
     scripts = List<ScriptRef>.from(
-        createServiceObject(json['scripts'], const ['ScriptRef']) ?? []);
+        createServiceObject(json['scripts'], const ['ScriptRef']) as List? ??
+            []);
   }
 
   @override
+  String get type => 'SourceReport';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'SourceReport';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'ranges': ranges.map((f) => f.toJson()).toList(),
       'scripts': scripts.map((f) => f.toJson()).toList(),
@@ -6546,8 +6783,7 @@
     return json;
   }
 
-  String toString() =>
-      '[SourceReport type: ${type}, ranges: ${ranges}, scripts: ${scripts}]';
+  String toString() => '[SourceReport ranges: ${ranges}, scripts: ${scripts}]';
 }
 
 /// The `SourceReportCoverage` class represents coverage information for one
@@ -6556,20 +6792,20 @@
 /// Note that `SourceReportCoverage` does not extend [Response] and therefore
 /// will not contain a `type` property.
 class SourceReportCoverage {
-  static SourceReportCoverage parse(Map<String, dynamic> json) =>
+  static SourceReportCoverage? parse(Map<String, dynamic>? json) =>
       json == null ? null : SourceReportCoverage._fromJson(json);
 
   /// A list of token positions in a SourceReportRange which have been executed.
   /// The list is sorted.
-  List<int> hits;
+  late final List<int> hits;
 
   /// A list of token positions in a SourceReportRange which have not been
   /// executed.  The list is sorted.
-  List<int> misses;
+  late final List<int> misses;
 
   SourceReportCoverage({
-    @required this.hits,
-    @required this.misses,
+    required this.hits,
+    required this.misses,
   });
 
   SourceReportCoverage._fromJson(Map<String, dynamic> json) {
@@ -6578,7 +6814,7 @@
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'hits': hits.map((f) => f).toList(),
       'misses': misses.map((f) => f).toList(),
@@ -6597,64 +6833,64 @@
 /// Note that `SourceReportRange` does not extend [Response] and therefore will
 /// not contain a `type` property.
 class SourceReportRange {
-  static SourceReportRange parse(Map<String, dynamic> json) =>
+  static SourceReportRange? parse(Map<String, dynamic>? json) =>
       json == null ? null : SourceReportRange._fromJson(json);
 
   /// An index into the script table of the SourceReport, indicating which
   /// script contains this range of code.
-  int scriptIndex;
+  late final int scriptIndex;
 
   /// The token position at which this range begins.
-  int startPos;
+  late final int startPos;
 
   /// The token position at which this range ends.  Inclusive.
-  int endPos;
+  late final int endPos;
 
   /// Has this range been compiled by the Dart VM?
-  bool compiled;
+  late final bool compiled;
 
   /// The error while attempting to compile this range, if this report was
   /// generated with forceCompile=true.
   @optional
-  ErrorRef error;
+  late final ErrorRef? error;
 
   /// Code coverage information for this range.  Provided only when the Coverage
   /// report has been requested and the range has been compiled.
   @optional
-  SourceReportCoverage coverage;
+  late final SourceReportCoverage? coverage;
 
   /// Possible breakpoint information for this range, represented as a sorted
   /// list of token positions.  Provided only when the when the
   /// PossibleBreakpoint report has been requested and the range has been
   /// compiled.
   @optional
-  List<int> possibleBreakpoints;
+  late final List<int>? possibleBreakpoints;
 
   SourceReportRange({
-    @required this.scriptIndex,
-    @required this.startPos,
-    @required this.endPos,
-    @required this.compiled,
+    required this.scriptIndex,
+    required this.startPos,
+    required this.endPos,
+    required this.compiled,
     this.error,
     this.coverage,
     this.possibleBreakpoints,
   });
 
   SourceReportRange._fromJson(Map<String, dynamic> json) {
-    scriptIndex = json['scriptIndex'];
-    startPos = json['startPos'];
-    endPos = json['endPos'];
-    compiled = json['compiled'];
-    error = createServiceObject(json['error'], const ['ErrorRef']);
+    scriptIndex = json['scriptIndex'] ?? -1;
+    startPos = json['startPos'] ?? -1;
+    endPos = json['endPos'] ?? -1;
+    compiled = json['compiled'] ?? false;
+    error = createServiceObject(json['error'], const ['ErrorRef']) as ErrorRef?;
     coverage =
-        _createSpecificObject(json['coverage'], SourceReportCoverage.parse);
+        _createSpecificObject(json['coverage']!, SourceReportCoverage.parse);
     possibleBreakpoints = json['possibleBreakpoints'] == null
         ? null
         : List<int>.from(json['possibleBreakpoints']);
   }
 
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
+    final json = <String, dynamic>{};
     json.addAll({
       'scriptIndex': scriptIndex,
       'startPos': startPos,
@@ -6664,7 +6900,7 @@
     _setIfNotNull(json, 'error', error?.toJson());
     _setIfNotNull(json, 'coverage', coverage?.toJson());
     _setIfNotNull(json, 'possibleBreakpoints',
-        possibleBreakpoints?.map((f) => f)?.toList());
+        possibleBreakpoints?.map((f) => f).toList());
     return json;
   }
 
@@ -6678,80 +6914,85 @@
 ///
 /// See [getStack].
 class Stack extends Response {
-  static Stack parse(Map<String, dynamic> json) =>
+  static Stack? parse(Map<String, dynamic>? json) =>
       json == null ? null : Stack._fromJson(json);
 
   /// A list of frames that make up the synchronous stack, rooted at the message
   /// loop (i.e., the frames since the last asynchronous gap or the isolate's
   /// entrypoint).
-  List<Frame> frames;
+  late final List<Frame> frames;
 
   /// A list of frames representing the asynchronous path. Comparable to
   /// `awaiterFrames`, if provided, although some frames may be different.
   @optional
-  List<Frame> asyncCausalFrames;
+  late final List<Frame>? asyncCausalFrames;
 
   /// A list of frames representing the asynchronous path. Comparable to
   /// `asyncCausalFrames`, if provided, although some frames may be different.
   @optional
-  List<Frame> awaiterFrames;
+  late final List<Frame>? awaiterFrames;
 
   /// A list of messages in the isolate's message queue.
-  List<Message> messages;
+  late final List<Message> messages;
 
   /// Specifies whether or not this stack is complete or has been artificially
   /// truncated.
-  bool truncated;
+  late final bool truncated;
 
   Stack({
-    @required this.frames,
-    @required this.messages,
-    @required this.truncated,
+    required this.frames,
+    required this.messages,
+    required this.truncated,
     this.asyncCausalFrames,
     this.awaiterFrames,
   });
 
   Stack._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
     frames = List<Frame>.from(
-        createServiceObject(json['frames'], const ['Frame']) ?? []);
+        createServiceObject(json['frames'], const ['Frame']) as List? ?? []);
     asyncCausalFrames = json['asyncCausalFrames'] == null
         ? null
         : List<Frame>.from(
-            createServiceObject(json['asyncCausalFrames'], const ['Frame']));
+            createServiceObject(json['asyncCausalFrames'], const ['Frame'])!
+                as List);
     awaiterFrames = json['awaiterFrames'] == null
         ? null
         : List<Frame>.from(
-            createServiceObject(json['awaiterFrames'], const ['Frame']));
+            createServiceObject(json['awaiterFrames'], const ['Frame'])!
+                as List);
     messages = List<Message>.from(
-        createServiceObject(json['messages'], const ['Message']) ?? []);
-    truncated = json['truncated'];
+        createServiceObject(json['messages'], const ['Message']) as List? ??
+            []);
+    truncated = json['truncated'] ?? false;
   }
 
   @override
+  String get type => 'Stack';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Stack';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'frames': frames.map((f) => f.toJson()).toList(),
       'messages': messages.map((f) => f.toJson()).toList(),
       'truncated': truncated,
     });
     _setIfNotNull(json, 'asyncCausalFrames',
-        asyncCausalFrames?.map((f) => f?.toJson())?.toList());
-    _setIfNotNull(json, 'awaiterFrames',
-        awaiterFrames?.map((f) => f?.toJson())?.toList());
+        asyncCausalFrames?.map((f) => f.toJson()).toList());
+    _setIfNotNull(
+        json, 'awaiterFrames', awaiterFrames?.map((f) => f.toJson()).toList());
     return json;
   }
 
   String toString() => '[Stack ' //
-      'type: ${type}, frames: ${frames}, messages: ${messages}, ' //
-      'truncated: ${truncated}]';
+      'frames: ${frames}, messages: ${messages}, truncated: ${truncated}]';
 }
 
 /// The `Success` type is used to indicate that an operation completed
 /// successfully.
 class Success extends Response {
-  static Success parse(Map<String, dynamic> json) =>
+  static Success? parse(Map<String, dynamic>? json) =>
       json == null ? null : Success._fromJson(json);
 
   Success();
@@ -6759,48 +7000,55 @@
   Success._fromJson(Map<String, dynamic> json) : super._fromJson(json);
 
   @override
+  String get type => 'Success';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Success';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     return json;
   }
 
-  String toString() => '[Success type: ${type}]';
+  String toString() => '[Success]';
 }
 
 class Timeline extends Response {
-  static Timeline parse(Map<String, dynamic> json) =>
+  static Timeline? parse(Map<String, dynamic>? json) =>
       json == null ? null : Timeline._fromJson(json);
 
   /// A list of timeline events. No order is guarenteed for these events; in
   /// particular, these events may be unordered with respect to their
   /// timestamps.
-  List<TimelineEvent> traceEvents;
+  late final List<TimelineEvent> traceEvents;
 
   /// The start of the period of time in which traceEvents were collected.
-  int timeOriginMicros;
+  late final int timeOriginMicros;
 
   /// The duration of time covered by the timeline.
-  int timeExtentMicros;
+  late final int timeExtentMicros;
 
   Timeline({
-    @required this.traceEvents,
-    @required this.timeOriginMicros,
-    @required this.timeExtentMicros,
+    required this.traceEvents,
+    required this.timeOriginMicros,
+    required this.timeExtentMicros,
   });
 
   Timeline._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
     traceEvents = List<TimelineEvent>.from(
-        createServiceObject(json['traceEvents'], const ['TimelineEvent']) ??
+        createServiceObject(json['traceEvents'], const ['TimelineEvent'])
+                as List? ??
             []);
-    timeOriginMicros = json['timeOriginMicros'];
-    timeExtentMicros = json['timeExtentMicros'];
+    timeOriginMicros = json['timeOriginMicros'] ?? -1;
+    timeExtentMicros = json['timeExtentMicros'] ?? -1;
   }
 
   @override
+  String get type => 'Timeline';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Timeline';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'traceEvents': traceEvents.map((f) => f.toJson()).toList(),
       'timeOriginMicros': timeOriginMicros,
@@ -6810,62 +7058,68 @@
   }
 
   String toString() => '[Timeline ' //
-      'type: ${type}, traceEvents: ${traceEvents}, timeOriginMicros: ${timeOriginMicros}, ' //
+      'traceEvents: ${traceEvents}, timeOriginMicros: ${timeOriginMicros}, ' //
       'timeExtentMicros: ${timeExtentMicros}]';
 }
 
 /// An `TimelineEvent` is an arbitrary map that contains a [Trace Event Format]
 /// event.
 class TimelineEvent {
-  static TimelineEvent parse(Map<String, dynamic> json) =>
+  static TimelineEvent? parse(Map<String, dynamic>? json) =>
       json == null ? null : TimelineEvent._fromJson(json);
 
-  Map<String, dynamic> json;
+  Map<String, dynamic>? json;
 
   TimelineEvent();
 
   TimelineEvent._fromJson(this.json);
 
   Map<String, dynamic> toJson() {
-    var result = json == null ? <String, dynamic>{} : Map.of(json);
+    final localJson = json;
+    final result = localJson == null
+        ? <String, dynamic>{}
+        : Map<String, dynamic>.of(localJson);
     result['type'] = 'TimelineEvent';
     return result;
   }
 
-  String toString() => '[TimelineEvent ]';
+  String toString() => '[TimelineEvent]';
 }
 
 class TimelineFlags extends Response {
-  static TimelineFlags parse(Map<String, dynamic> json) =>
+  static TimelineFlags? parse(Map<String, dynamic>? json) =>
       json == null ? null : TimelineFlags._fromJson(json);
 
   /// The name of the recorder currently in use. Recorder types include, but are
   /// not limited to: Callback, Endless, Fuchsia, Macos, Ring, Startup, and
   /// Systrace. Set to "null" if no recorder is currently set.
-  String recorderName;
+  late final String recorderName;
 
   /// The list of all available timeline streams.
-  List<String> availableStreams;
+  late final List<String> availableStreams;
 
   /// The list of timeline streams that are currently enabled.
-  List<String> recordedStreams;
+  late final List<String> recordedStreams;
 
   TimelineFlags({
-    @required this.recorderName,
-    @required this.availableStreams,
-    @required this.recordedStreams,
+    required this.recorderName,
+    required this.availableStreams,
+    required this.recordedStreams,
   });
 
   TimelineFlags._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    recorderName = json['recorderName'];
+    recorderName = json['recorderName'] ?? '';
     availableStreams = List<String>.from(json['availableStreams']);
     recordedStreams = List<String>.from(json['recordedStreams']);
   }
 
   @override
+  String get type => 'TimelineFlags';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'TimelineFlags';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'recorderName': recorderName,
       'availableStreams': availableStreams.map((f) => f).toList(),
@@ -6875,60 +7129,68 @@
   }
 
   String toString() => '[TimelineFlags ' //
-      'type: ${type}, recorderName: ${recorderName}, availableStreams: ${availableStreams}, ' //
+      'recorderName: ${recorderName}, availableStreams: ${availableStreams}, ' //
       'recordedStreams: ${recordedStreams}]';
 }
 
 class Timestamp extends Response {
-  static Timestamp parse(Map<String, dynamic> json) =>
+  static Timestamp? parse(Map<String, dynamic>? json) =>
       json == null ? null : Timestamp._fromJson(json);
 
   /// A timestamp in microseconds since epoch.
-  int timestamp;
+  late final int timestamp;
 
   Timestamp({
-    @required this.timestamp,
+    required this.timestamp,
   });
 
   Timestamp._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    timestamp = json['timestamp'];
+    timestamp = json['timestamp'] ?? -1;
   }
 
   @override
+  String get type => 'Timestamp';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Timestamp';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'timestamp': timestamp,
     });
     return json;
   }
 
-  String toString() => '[Timestamp type: ${type}, timestamp: ${timestamp}]';
+  String toString() => '[Timestamp timestamp: ${timestamp}]';
 }
 
 /// `TypeArgumentsRef` is a reference to a `TypeArguments` object.
 class TypeArgumentsRef extends ObjRef {
-  static TypeArgumentsRef parse(Map<String, dynamic> json) =>
+  static TypeArgumentsRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : TypeArgumentsRef._fromJson(json);
 
   /// A name for this type argument list.
-  String name;
+  late final String name;
 
   TypeArgumentsRef({
-    @required this.name,
-    @required String id,
-  }) : super(id: id);
+    required this.name,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   TypeArgumentsRef._fromJson(Map<String, dynamic> json)
       : super._fromJson(json) {
-    name = json['name'];
+    name = json['name'] ?? '';
   }
 
   @override
+  String get type => 'TypeArgumentsRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = '@TypeArguments';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
     });
@@ -6939,41 +7201,46 @@
 
   operator ==(other) => other is TypeArgumentsRef && id == other.id;
 
-  String toString() =>
-      '[TypeArgumentsRef type: ${type}, id: ${id}, name: ${name}]';
+  String toString() => '[TypeArgumentsRef id: ${id}, name: ${name}]';
 }
 
 /// A `TypeArguments` object represents the type argument vector for some
 /// instantiated generic type.
 class TypeArguments extends Obj implements TypeArgumentsRef {
-  static TypeArguments parse(Map<String, dynamic> json) =>
+  static TypeArguments? parse(Map<String, dynamic>? json) =>
       json == null ? null : TypeArguments._fromJson(json);
 
   /// A name for this type argument list.
-  String name;
+  late final String name;
 
   /// A list of types.
   ///
   /// The value will always be one of the kinds: Type, TypeRef, TypeParameter,
   /// BoundedType.
-  List<InstanceRef> types;
+  late final List<InstanceRef> types;
 
   TypeArguments({
-    @required this.name,
-    @required this.types,
-    @required String id,
-  }) : super(id: id);
+    required this.name,
+    required this.types,
+    required String id,
+  }) : super(
+          id: id,
+        );
 
   TypeArguments._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
+    name = json['name'] ?? '';
     types = List<InstanceRef>.from(
-        createServiceObject(json['types'], const ['InstanceRef']) ?? []);
+        createServiceObject(json['types'], const ['InstanceRef']) as List? ??
+            []);
   }
 
   @override
+  String get type => 'TypeArguments';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = super.toJson();
-    json['type'] = 'TypeArguments';
+    final json = super.toJson();
+    json['type'] = type;
     json.addAll({
       'name': name,
       'types': types.map((f) => f.toJson()).toList(),
@@ -6986,7 +7253,7 @@
   operator ==(other) => other is TypeArguments && id == other.id;
 
   String toString() =>
-      '[TypeArguments type: ${type}, id: ${id}, name: ${name}, types: ${types}]';
+      '[TypeArguments id: ${id}, name: ${name}, types: ${types}]';
 }
 
 /// The `UnresolvedSourceLocation` class is used to refer to an unresolved
@@ -7000,32 +7267,32 @@
 /// The `column` field will only be present when the breakpoint was specified
 /// with a specific column number.
 class UnresolvedSourceLocation extends Response {
-  static UnresolvedSourceLocation parse(Map<String, dynamic> json) =>
+  static UnresolvedSourceLocation? parse(Map<String, dynamic>? json) =>
       json == null ? null : UnresolvedSourceLocation._fromJson(json);
 
   /// The script containing the source location if the script has been loaded.
   @optional
-  ScriptRef script;
+  late final ScriptRef? script;
 
   /// The uri of the script containing the source location if the script has yet
   /// to be loaded.
   @optional
-  String scriptUri;
+  late final String? scriptUri;
 
   /// An approximate token position for the source location. This may change
   /// when the location is resolved.
   @optional
-  int tokenPos;
+  late final int? tokenPos;
 
   /// An approximate line number for the source location. This may change when
   /// the location is resolved.
   @optional
-  int line;
+  late final int? line;
 
   /// An approximate column number for the source location. This may change when
   /// the location is resolved.
   @optional
-  int column;
+  late final int? column;
 
   UnresolvedSourceLocation({
     this.script,
@@ -7037,7 +7304,8 @@
 
   UnresolvedSourceLocation._fromJson(Map<String, dynamic> json)
       : super._fromJson(json) {
-    script = createServiceObject(json['script'], const ['ScriptRef']);
+    script =
+        createServiceObject(json['script'], const ['ScriptRef']) as ScriptRef?;
     scriptUri = json['scriptUri'];
     tokenPos = json['tokenPos'];
     line = json['line'];
@@ -7045,9 +7313,12 @@
   }
 
   @override
+  String get type => 'UnresolvedSourceLocation';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'UnresolvedSourceLocation';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     _setIfNotNull(json, 'script', script?.toJson());
     _setIfNotNull(json, 'scriptUri', scriptUri);
     _setIfNotNull(json, 'tokenPos', tokenPos);
@@ -7056,36 +7327,39 @@
     return json;
   }
 
-  String toString() => '[UnresolvedSourceLocation type: ${type}]';
+  String toString() => '[UnresolvedSourceLocation]';
 }
 
 /// See [Versioning].
 class Version extends Response {
-  static Version parse(Map<String, dynamic> json) =>
+  static Version? parse(Map<String, dynamic>? json) =>
       json == null ? null : Version._fromJson(json);
 
   /// The major version number is incremented when the protocol is changed in a
   /// potentially incompatible way.
-  int major;
+  late final int major;
 
   /// The minor version number is incremented when the protocol is changed in a
   /// backwards compatible way.
-  int minor;
+  late final int minor;
 
   Version({
-    @required this.major,
-    @required this.minor,
+    required this.major,
+    required this.minor,
   });
 
   Version._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    major = json['major'];
-    minor = json['minor'];
+    major = json['major'] ?? -1;
+    minor = json['minor'] ?? -1;
   }
 
   @override
+  String get type => 'Version';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'Version';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'major': major,
       'minor': minor,
@@ -7093,122 +7367,130 @@
     return json;
   }
 
-  String toString() =>
-      '[Version type: ${type}, major: ${major}, minor: ${minor}]';
+  String toString() => '[Version major: ${major}, minor: ${minor}]';
 }
 
 /// `VMRef` is a reference to a `VM` object.
 class VMRef extends Response {
-  static VMRef parse(Map<String, dynamic> json) =>
+  static VMRef? parse(Map<String, dynamic>? json) =>
       json == null ? null : VMRef._fromJson(json);
 
   /// A name identifying this vm. Not guaranteed to be unique.
-  String name;
+  late final String name;
 
   VMRef({
-    @required this.name,
+    required this.name,
   });
 
   VMRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
+    name = json['name'] ?? '';
   }
 
   @override
+  String get type => 'VMRef';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = '@VM';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'name': name,
     });
     return json;
   }
 
-  String toString() => '[VMRef type: ${type}, name: ${name}]';
+  String toString() => '[VMRef name: ${name}]';
 }
 
 class VM extends Response implements VMRef {
-  static VM parse(Map<String, dynamic> json) =>
+  static VM? parse(Map<String, dynamic>? json) =>
       json == null ? null : VM._fromJson(json);
 
   /// A name identifying this vm. Not guaranteed to be unique.
-  String name;
+  late final String name;
 
   /// Word length on target architecture (e.g. 32, 64).
-  int architectureBits;
+  late final int architectureBits;
 
   /// The CPU we are actually running on.
-  String hostCPU;
+  late final String hostCPU;
 
   /// The operating system we are running on.
-  String operatingSystem;
+  late final String operatingSystem;
 
   /// The CPU we are generating code for.
-  String targetCPU;
+  late final String targetCPU;
 
   /// The Dart VM version string.
-  String version;
+  late final String version;
 
   /// The process id for the VM.
-  int pid;
+  late final int pid;
 
   /// The time that the VM started in milliseconds since the epoch.
   ///
   /// Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
-  int startTime;
+  late final int startTime;
 
   /// A list of isolates running in the VM.
-  List<IsolateRef> isolates;
+  late final List<IsolateRef> isolates;
 
   /// A list of isolate groups running in the VM.
-  List<IsolateGroupRef> isolateGroups;
+  late final List<IsolateGroupRef> isolateGroups;
 
   /// A list of system isolates running in the VM.
-  List<IsolateRef> systemIsolates;
+  late final List<IsolateRef> systemIsolates;
 
   /// A list of isolate groups which contain system isolates running in the VM.
-  List<IsolateGroupRef> systemIsolateGroups;
+  late final List<IsolateGroupRef> systemIsolateGroups;
 
   VM({
-    @required this.name,
-    @required this.architectureBits,
-    @required this.hostCPU,
-    @required this.operatingSystem,
-    @required this.targetCPU,
-    @required this.version,
-    @required this.pid,
-    @required this.startTime,
-    @required this.isolates,
-    @required this.isolateGroups,
-    @required this.systemIsolates,
-    @required this.systemIsolateGroups,
+    required this.name,
+    required this.architectureBits,
+    required this.hostCPU,
+    required this.operatingSystem,
+    required this.targetCPU,
+    required this.version,
+    required this.pid,
+    required this.startTime,
+    required this.isolates,
+    required this.isolateGroups,
+    required this.systemIsolates,
+    required this.systemIsolateGroups,
   });
 
   VM._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
-    name = json['name'];
-    architectureBits = json['architectureBits'];
-    hostCPU = json['hostCPU'];
-    operatingSystem = json['operatingSystem'];
-    targetCPU = json['targetCPU'];
-    version = json['version'];
-    pid = json['pid'];
-    startTime = json['startTime'];
+    name = json['name'] ?? '';
+    architectureBits = json['architectureBits'] ?? -1;
+    hostCPU = json['hostCPU'] ?? '';
+    operatingSystem = json['operatingSystem'] ?? '';
+    targetCPU = json['targetCPU'] ?? '';
+    version = json['version'] ?? '';
+    pid = json['pid'] ?? -1;
+    startTime = json['startTime'] ?? -1;
     isolates = List<IsolateRef>.from(
-        createServiceObject(json['isolates'], const ['IsolateRef']) ?? []);
+        createServiceObject(json['isolates'], const ['IsolateRef']) as List? ??
+            []);
     isolateGroups = List<IsolateGroupRef>.from(
-        createServiceObject(json['isolateGroups'], const ['IsolateGroupRef']) ??
+        createServiceObject(json['isolateGroups'], const ['IsolateGroupRef'])
+                as List? ??
             []);
     systemIsolates = List<IsolateRef>.from(
-        createServiceObject(json['systemIsolates'], const ['IsolateRef']) ??
+        createServiceObject(json['systemIsolates'], const ['IsolateRef'])
+                as List? ??
             []);
     systemIsolateGroups = List<IsolateGroupRef>.from(createServiceObject(
-            json['systemIsolateGroups'], const ['IsolateGroupRef']) ??
+            json['systemIsolateGroups'], const ['IsolateGroupRef']) as List? ??
         []);
   }
 
   @override
+  String get type => 'VM';
+
+  @override
   Map<String, dynamic> toJson() {
-    var json = <String, dynamic>{};
-    json['type'] = 'VM';
+    final json = <String, dynamic>{};
+    json['type'] = type;
     json.addAll({
       'name': name,
       'architectureBits': architectureBits,
diff --git a/pkg/vm_service/lib/utils.dart b/pkg/vm_service/lib/utils.dart
index dd6ffbc..9f65a66 100644
--- a/pkg/vm_service/lib/utils.dart
+++ b/pkg/vm_service/lib/utils.dart
@@ -2,12 +2,10 @@
 // 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 'package:meta/meta.dart';
-
 /// Map the URI to a WebSocket URI for the VM service protocol.
 ///
 /// If the URI is already a VM Service WebSocket URI it will not be modified.
-Uri convertToWebSocketUrl({@required Uri serviceProtocolUrl}) {
+Uri convertToWebSocketUrl({required Uri serviceProtocolUrl}) {
   final isSecure = serviceProtocolUrl.isScheme('wss') ||
       serviceProtocolUrl.isScheme('https');
   final scheme = isSecure ? 'wss' : 'ws';
diff --git a/pkg/vm_service/lib/vm_service_io.dart b/pkg/vm_service/lib/vm_service_io.dart
index 00597af..0db488b 100644
--- a/pkg/vm_service/lib/vm_service_io.dart
+++ b/pkg/vm_service/lib/vm_service_io.dart
@@ -8,7 +8,7 @@
 import 'vm_service.dart';
 
 @Deprecated('Prefer vmServiceConnectUri')
-Future<VmService> vmServiceConnect(String host, int port, {Log log}) async {
+Future<VmService> vmServiceConnect(String host, int port, {Log? log}) async {
   final WebSocket socket = await WebSocket.connect('ws://$host:$port/ws');
   final StreamController<dynamic> controller = StreamController();
   final Completer streamClosedCompleter = Completer();
@@ -28,7 +28,7 @@
 }
 
 /// Connect to the given uri and return a new [VmService] instance.
-Future<VmService> vmServiceConnectUri(String wsUri, {Log log}) async {
+Future<VmService> vmServiceConnectUri(String wsUri, {Log? log}) async {
   final WebSocket socket = await WebSocket.connect(wsUri);
   final StreamController<dynamic> controller = StreamController();
   final Completer streamClosedCompleter = Completer();
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 7f1f7af..e4ff937 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,21 +2,21 @@
 description: >-
   A library to communicate with a service implementing the Dart VM
   service protocol.
-version: 5.5.1
+
+version: 6.0.0-nullsafety-dev
 
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
 
 environment:
-  sdk: '>=2.6.0 <3.0.0'
+  sdk: '>=2.12.0-0 <3.0.0'
 
 dependencies:
-  meta: ^1.0.2
 
 dev_dependencies:
-  async: ^2.0.0
-  markdown: ^2.0.0
-  mockito: ^4.0.0
-  path: ^1.0.0
-  pedantic: ^1.7.0
-  pub_semver: ^1.0.0
-  test: ^1.0.0
+  async: ^2.5.0-nullsafety.3
+  markdown: ^4.0.0-nullsafety.0
+  mockito: ^5.0.0-nullsafety.1
+  path: ^1.8.0-nullsafety.3
+  pedantic: ^1.10.0-nullsafety.3
+  pub_semver: ^2.0.0-nullsafety.0
+  test: ^1.16.0-nullsafety.13
diff --git a/pkg/vm_service/test/async_generator_breakpoint_test.dart b/pkg/vm_service/test/async_generator_breakpoint_test.dart
index e709594..d6e8e65 100644
--- a/pkg/vm_service/test/async_generator_breakpoint_test.dart
+++ b/pkg/vm_service/test/async_generator_breakpoint_test.dart
@@ -47,7 +47,8 @@
 
 Future testAsync(VmService service, IsolateRef isolateRef) async {
   final isolate = await service.getIsolate(isolateRef.id);
-  final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
+  final Library lib =
+      (await service.getObject(isolate.id, isolate.rootLib!.id)) as Library;
   final script = lib.scripts[0];
 
   final bp1 = await service.addBreakpoint(isolate.id, script.id, 11);
@@ -85,8 +86,8 @@
   final stream = service.onDebugEvent;
   await for (Event event in stream) {
     if (event.kind == EventKind.kPauseBreakpoint) {
-      assert(event.pauseBreakpoints.isNotEmpty);
-      final bp = event.pauseBreakpoints.first;
+      assert(event.pauseBreakpoints!.isNotEmpty);
+      final bp = event.pauseBreakpoints!.first;
       hits.add(bp);
       await service.resume(isolate.id);
 
diff --git a/pkg/vm_service/test/async_scope_test.dart b/pkg/vm_service/test/async_scope_test.dart
index 9573e69..4304553 100644
--- a/pkg/vm_service/test/async_scope_test.dart
+++ b/pkg/vm_service/test/async_scope_test.dart
@@ -34,20 +34,20 @@
 }
 
 Future<void> checkAsyncVarDescriptors(
-    VmService service, IsolateRef isolateRef) async {
-  final stack = await service.getStack(isolateRef.id);
+    VmService? service, IsolateRef? isolateRef) async {
+  final stack = await service!.getStack(isolateRef!.id);
   expect(stack.frames.length, greaterThanOrEqualTo(1));
   final frame = stack.frames[0];
-  final vars = frame.vars.map((v) => v.name).join(' ');
+  final vars = frame.vars!.map((v) => v.name).join(' ');
   expect(vars, 'param1 local1'); // no :async_op et al
 }
 
 Future checkAsyncStarVarDescriptors(
-    VmService service, IsolateRef isolateRef) async {
-  final stack = await service.getStack(isolateRef.id);
+    VmService? service, IsolateRef? isolateRef) async {
+  final stack = await service!.getStack(isolateRef!.id);
   expect(stack.frames.length, greaterThanOrEqualTo(1));
   final frame = stack.frames[0];
-  final vars = frame.vars.map((v) => v.name).join(' ');
+  final vars = frame.vars!.map((v) => v.name).join(' ');
   expect(vars, 'param2 local2'); // no :async_op et al
 }
 
diff --git a/pkg/vm_service/test/common/service_test_common.dart b/pkg/vm_service/test/common/service_test_common.dart
index 56a6304..e54d930 100644
--- a/pkg/vm_service/test/common/service_test_common.dart
+++ b/pkg/vm_service/test/common/service_test_common.dart
@@ -15,11 +15,10 @@
 Future<void> smartNext(VmService service, IsolateRef isolateRef) async {
   print('smartNext');
   final isolate = await service.getIsolate(isolateRef.id);
-  if ((isolate.pauseEvent != null) &&
-      (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+  if ((isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
     Event event = isolate.pauseEvent;
     // TODO(bkonyi): remove needless refetching of isolate object.
-    if (event?.atAsyncSuspension ?? false) {
+    if (event.atAsyncSuspension ?? false) {
       return asyncNext(service, isolateRef);
     } else {
       return syncNext(service, isolateRef);
@@ -32,13 +31,12 @@
 Future<void> asyncNext(VmService service, IsolateRef isolateRef) async {
   print('asyncNext');
   final isolate = await service.getIsolate(isolateRef.id);
-  if ((isolate.pauseEvent != null) &&
-      (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+  if ((isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
     dynamic event = isolate.pauseEvent;
     if (!event.atAsyncSuspension) {
       throw 'No async continuation at this location';
     } else {
-      return service.resume(isolateRef.id, step: 'OverAsyncSuspension');
+      await service.resume(isolateRef.id, step: 'OverAsyncSuspension');
     }
   } else {
     throw 'The program is already running';
@@ -48,9 +46,8 @@
 Future<void> syncNext(VmService service, IsolateRef isolateRef) async {
   print('syncNext');
   final isolate = await service.getIsolate(isolateRef.id);
-  if ((isolate.pauseEvent != null) &&
-      (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
-    return service.resume(isolate.id, step: 'Over');
+  if ((isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+    await service.resume(isolate.id, step: 'Over');
   } else {
     throw 'The program is already running';
   }
@@ -58,10 +55,10 @@
 
 Future<void> hasPausedFor(
     VmService service, IsolateRef isolateRef, String kind) async {
-  var completer = Completer();
-  var subscription;
+  Completer<dynamic>? completer = Completer();
+  late var subscription;
   subscription = service.onDebugEvent.listen((event) async {
-    if ((isolateRef.id == event.isolate.id) && (event.kind == kind)) {
+    if ((isolateRef.id == event.isolate!.id) && (event.kind == kind)) {
       if (completer != null) {
         try {
           await service.streamCancel(EventStreams.kDebug);
@@ -78,7 +75,7 @@
 
   // Pause may have happened before we subscribed.
   final isolate = await service.getIsolate(isolateRef.id);
-  if ((isolate.pauseEvent != null) && (isolate.pauseEvent.kind == kind)) {
+  if ((isolate.pauseEvent.kind == kind)) {
     if (completer != null) {
       try {
         await service.streamCancel(EventStreams.kDebug);
@@ -117,7 +114,8 @@
   return (VmService service, IsolateRef isolateRef) async {
     print("Setting breakpoint for line $line");
     final isolate = await service.getIsolate(isolateRef.id);
-    final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
+    final Library lib =
+        (await service.getObject(isolate.id, isolate.rootLib!.id)) as Library;
     final script = lib.scripts.first;
 
     Breakpoint bpt = await service.addBreakpoint(isolate.id, script.id, line);
@@ -139,9 +137,9 @@
     expect(frames.length, greaterThanOrEqualTo(1));
 
     final top = frames[0];
-    final Script script =
-        await service.getObject(isolate.id, top.location.script.id);
-    int actualLine = script.getLineNumberFromTokenPos(top.location.tokenPos);
+    final Script script = (await service.getObject(
+        isolate.id, top.location!.script.id)) as Script;
+    int actualLine = script.getLineNumberFromTokenPos(top.location!.tokenPos)!;
     if (actualLine != line) {
       print("Actual: $actualLine Line: $line");
       final sb = StringBuffer();
@@ -149,7 +147,7 @@
       sb.write("\nFull stack trace:\n");
       for (Frame f in stack.frames) {
         sb.write(
-            " $f [${script.getLineNumberFromTokenPos(f.location.tokenPos)}]\n");
+            " $f [${script.getLineNumberFromTokenPos(f.location!.tokenPos)}]\n");
       }
       throw sb.toString();
     } else {
@@ -160,7 +158,7 @@
 
 Future<void> resumeIsolate(VmService service, IsolateRef isolate) async {
   Completer completer = Completer();
-  var subscription;
+  late var subscription;
   subscription = service.onDebugEvent.listen((event) async {
     if (event.kind == EventKind.kResume) {
       try {
diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart
index 48d5941..72ae563 100644
--- a/pkg/vm_service/test/common/test_helper.dart
+++ b/pkg/vm_service/test/common/test_helper.dart
@@ -18,8 +18,8 @@
 
 /// Will be set to the http address of the VM's service protocol before
 /// any tests are invoked.
-String serviceHttpAddress;
-String serviceWebsocketAddress;
+late String serviceHttpAddress;
+late String serviceWebsocketAddress;
 
 const String _TESTEE_ENV_KEY = 'SERVICE_TEST_TESTEE';
 const Map<String, String> _TESTEE_SPAWN_ENV = {_TESTEE_ENV_KEY: 'true'};
@@ -33,7 +33,7 @@
     // We'll need to parse the actual URI out...
     final fileRegExp = RegExp(r'file:\/\/\/.*\.dart');
     final path =
-        fileRegExp.stringMatch(io.Platform.script.data.contentAsString());
+        fileRegExp.stringMatch(io.Platform.script.data!.contentAsString());
     if (path == null) {
       throw 'Unable to determine file path for script!';
     }
@@ -45,8 +45,8 @@
 
 class _ServiceTesteeRunner {
   Future run(
-      {Function() testeeBefore,
-      Function() testeeConcurrent,
+      {Function()? testeeBefore,
+      Function()? testeeConcurrent,
       bool pause_on_start = false,
       bool pause_on_exit = false}) async {
     if (!pause_on_start) {
@@ -72,8 +72,8 @@
   }
 
   void runSync(
-      {void Function() testeeBeforeSync,
-      void Function() testeeConcurrentSync,
+      {void Function()? testeeBeforeSync,
+      void Function()? testeeConcurrentSync,
       bool pause_on_start = false,
       bool pause_on_exit = false}) {
     if (!pause_on_start) {
@@ -93,7 +93,7 @@
 }
 
 class _ServiceTesteeLauncher {
-  io.Process process;
+  io.Process? process;
   List<String> args;
   bool killedByTester = false;
 
@@ -106,13 +106,8 @@
     bool pause_on_unhandled_exceptions,
     bool testeeControlsServer,
     bool useAuthToken,
-    List<String> extraArgs,
+    List<String>? extraArgs,
   ) {
-    assert(pause_on_start != null);
-    assert(pause_on_exit != null);
-    assert(pause_on_unhandled_exceptions != null);
-    assert(testeeControlsServer != null);
-    assert(useAuthToken != null);
     return _spawnDartProcess(
         pause_on_start,
         pause_on_exit,
@@ -128,7 +123,7 @@
       bool pause_on_unhandled_exceptions,
       bool testeeControlsServer,
       bool useAuthToken,
-      List<String> extraArgs) {
+      List<String>? extraArgs) {
     String dartExecutable = io.Platform.executable;
 
     var fullArgs = <String>[
@@ -160,16 +155,14 @@
     return _spawnCommon(dartExecutable, fullArgs, <String, String>{});
   }
 
-  Future<io.Process> _spawnCommon(String executable, List<String> arguments,
-      Map<String, String> dartEnvironment) {
+  Future<io.Process> _spawnCommon(String executable,
+      List<String> /*!*/ arguments, Map<String, String> dartEnvironment) {
     var environment = _TESTEE_SPAWN_ENV;
     var bashEnvironment = StringBuffer();
     environment.forEach((k, v) => bashEnvironment.write("$k=$v "));
-    if (dartEnvironment != null) {
-      dartEnvironment.forEach((k, v) {
-        arguments.insert(0, '-D$k=$v');
-      });
-    }
+    dartEnvironment.forEach((k, v) {
+      arguments.insert(0, '-D$k=$v');
+    });
     print('** Launching $bashEnvironment$executable ${arguments.join(' ')}');
     return io.Process.start(executable, arguments, environment: environment);
   }
@@ -180,7 +173,7 @@
       bool pause_on_unhandled_exceptions,
       bool testeeControlsServer,
       bool useAuthToken,
-      List<String> extraArgs) {
+      List<String>? extraArgs) {
     return _spawnProcess(
             pause_on_start,
             pause_on_exit,
@@ -191,10 +184,10 @@
         .then((p) {
       Completer<Uri> completer = Completer<Uri>();
       process = p;
-      Uri uri;
+      Uri? uri;
       var blank;
       var first = true;
-      process.stdout
+      process!.stdout
           .transform(utf8.decoder)
           .transform(LineSplitter())
           .listen((line) {
@@ -214,15 +207,15 @@
         }
         io.stdout.write('>testee>out> ${line}\n');
       });
-      process.stderr
+      process!.stderr
           .transform(utf8.decoder)
           .transform(LineSplitter())
           .listen((line) {
         io.stdout.write('>testee>err> ${line}\n');
       });
-      process.exitCode.then((exitCode) {
+      process!.exitCode.then((exitCode) {
         if ((io.exitCode != 0) && !killedByTester) {
-          throw "Testee io.exited with $exitCode";
+          throw "Testee exited with $exitCode";
         }
         print("** Process exited");
       });
@@ -233,14 +226,14 @@
   void requestExit() {
     if (process != null) {
       print('** Killing script');
-      if (process.kill()) {
+      if (process!.kill()) {
         killedByTester = true;
       }
     }
   }
 }
 
-void setupAddresses(Uri serverAddress) {
+void setupAddresses(Uri /*!*/ serverAddress) {
   serviceWebsocketAddress =
       'ws://${serverAddress.authority}${serverAddress.path}ws';
   serviceHttpAddress = 'http://${serverAddress.authority}${serverAddress.path}';
@@ -248,10 +241,10 @@
 
 class _ServiceTesterRunner {
   Future run(
-      {List<String> mainArgs,
-      List<String> extraArgs,
-      List<VMTest> vmTests,
-      List<IsolateTest> isolateTests,
+      {List<String>? mainArgs,
+      List<String>? extraArgs,
+      List<VMTest>? vmTests,
+      List<IsolateTest>? isolateTests,
       bool pause_on_start = false,
       bool pause_on_exit = false,
       bool verbose_vm = false,
@@ -259,15 +252,15 @@
       bool testeeControlsServer = false,
       bool useAuthToken = false}) async {
     var process = _ServiceTesteeLauncher();
-    VmService vm;
-    IsolateRef isolate;
+    late VmService vm;
+    late IsolateRef isolate;
     setUp(() async {
       await process
           .launch(pause_on_start, pause_on_exit, pause_on_unhandled_exceptions,
               testeeControlsServer, useAuthToken, extraArgs)
           .then((Uri serverAddress) async {
-        if (mainArgs.contains("--gdb")) {
-          var pid = process.process.pid;
+        if (mainArgs!.contains("--gdb")) {
+          var pid = process.process!.pid;
           var wait = Duration(seconds: 10);
           print("Testee has pid $pid, waiting $wait before continuing");
           io.sleep(wait);
@@ -322,8 +315,8 @@
     if (vm.isolates.isNotEmpty) {
       return vm.isolates.first;
     }
-    var completer = Completer();
-    StreamSubscription subscription;
+    Completer<dynamic>? completer = Completer();
+    late StreamSubscription subscription;
     subscription = service.onIsolateEvent.listen((Event event) async {
       if (completer == null) {
         await subscription.cancel();
@@ -333,7 +326,7 @@
         vm = await service.getVM();
         assert(vm.isolates.isNotEmpty);
         await subscription.cancel();
-        completer.complete(vm.isolates.first);
+        completer!.complete(vm.isolates.first);
         completer = null;
       }
     });
@@ -342,10 +335,10 @@
     vm = await service.getVM();
     if (vm.isolates.isNotEmpty) {
       await subscription.cancel();
-      completer.complete(vm.isolates.first);
+      completer!.complete(vm.isolates.first);
       completer = null;
     }
-    return await completer.future;
+    return await (completer!.future as FutureOr<IsolateRef>);
   }
 }
 
@@ -356,15 +349,15 @@
 Future<void> runIsolateTests(
   List<String> mainArgs,
   List<IsolateTest> tests, {
-  testeeBefore(),
-  testeeConcurrent(),
+  testeeBefore()?,
+  testeeConcurrent()?,
   bool pause_on_start = false,
   bool pause_on_exit = false,
   bool verbose_vm = false,
   bool pause_on_unhandled_exceptions = false,
   bool testeeControlsServer = false,
   bool useAuthToken = false,
-  List<String> extraArgs,
+  List<String>? extraArgs,
 }) async {
   assert(!pause_on_start || testeeBefore == null);
   if (_isTestee()) {
@@ -399,13 +392,13 @@
 void runIsolateTestsSynchronous(
   List<String> mainArgs,
   List<IsolateTest> tests, {
-  void testeeBefore(),
-  void testeeConcurrent(),
+  void testeeBefore()?,
+  void testeeConcurrent()?,
   bool pause_on_start = false,
   bool pause_on_exit = false,
   bool verbose_vm = false,
   bool pause_on_unhandled_exceptions = false,
-  List<String> extraArgs,
+  List<String>? extraArgs,
 }) {
   assert(!pause_on_start || testeeBefore == null);
   if (_isTestee()) {
@@ -433,13 +426,13 @@
 Future<void> runVMTests(
   List<String> mainArgs,
   List<VMTest> tests, {
-  testeeBefore(),
-  testeeConcurrent(),
+  testeeBefore()?,
+  testeeConcurrent()?,
   bool pause_on_start = false,
   bool pause_on_exit = false,
   bool verbose_vm = false,
   bool pause_on_unhandled_exceptions = false,
-  List<String> extraArgs,
+  List<String>? extraArgs,
 }) async {
   if (_isTestee()) {
     await _ServiceTesteeRunner().run(
diff --git a/pkg/vm_service/test/coverage_leaf_function_test.dart b/pkg/vm_service/test/coverage_leaf_function_test.dart
index eac959f..42cd1a0 100644
--- a/pkg/vm_service/test/coverage_leaf_function_test.dart
+++ b/pkg/vm_service/test/coverage_leaf_function_test.dart
@@ -35,10 +35,10 @@
 
     // Make sure we are in the right place.
     expect(stack.frames.length, greaterThanOrEqualTo(1));
-    expect(stack.frames[0].function.name, 'testFunction');
+    expect(stack.frames[0].function!.name, 'testFunction');
 
     final Library root =
-        await service.getObject(isolate.id, isolate.rootLib.id);
+        await service.getObject(isolate.id, isolate.rootLib!.id) as Library;
     FuncRef funcRef =
         root.functions.singleWhere((f) => f.name == 'leafFunction');
     Func func = await service.getObject(isolate.id, funcRef.id) as Func;
@@ -53,12 +53,13 @@
         'misses': [397]
       }
     };
+    final location = func.location!;
 
     final report = await service.getSourceReport(
         isolate.id, [SourceReportKind.kCoverage],
-        scriptId: func.location.script.id,
-        tokenPos: func.location.tokenPos,
-        endTokenPos: func.location.endTokenPos,
+        scriptId: location.script.id,
+        tokenPos: location.tokenPos,
+        endTokenPos: location.endTokenPos,
         forceCompile: true);
     expect(report.ranges.length, 1);
     expect(report.ranges[0].toJson(), expectedRange);
@@ -73,10 +74,10 @@
 
     // Make sure we are in the right place.
     expect(stack.frames.length, greaterThanOrEqualTo(1));
-    expect(stack.frames[0].function.name, 'testFunction');
+    expect(stack.frames[0].function!.name, 'testFunction');
 
     final Library root =
-        await service.getObject(isolate.id, isolate.rootLib.id);
+        await service.getObject(isolate.id, isolate.rootLib!.id) as Library;
     FuncRef funcRef =
         root.functions.singleWhere((f) => f.name == 'leafFunction');
     Func func = await service.getObject(isolate.id, funcRef.id) as Func;
@@ -92,11 +93,12 @@
       }
     };
 
+    final location = func.location!;
     final report = await service.getSourceReport(
         isolate.id, [SourceReportKind.kCoverage],
-        scriptId: func.location.script.id,
-        tokenPos: func.location.tokenPos,
-        endTokenPos: func.location.endTokenPos,
+        scriptId: location.script.id,
+        tokenPos: location.tokenPos,
+        endTokenPos: location.endTokenPos,
         forceCompile: true);
     expect(report.ranges.length, 1);
     expect(report.ranges[0].toJson(), expectedRange);
diff --git a/pkg/vm_service/test/debugging_test.dart b/pkg/vm_service/test/debugging_test.dart
index d5c1b9e..068af19 100644
--- a/pkg/vm_service/test/debugging_test.dart
+++ b/pkg/vm_service/test/debugging_test.dart
@@ -25,14 +25,14 @@
 }
 
 int getLineNumberFromTokenPos(Script s, int token) =>
-    s.tokenPosTable[token].first;
+    s.tokenPosTable![token].first;
 
 var tests = <IsolateTest>[
 // Pause
-  (VmService service, IsolateRef isolateRef) async {
+  (VmService? service, IsolateRef? isolateRef) async {
     Completer completer = Completer();
-    var stream = service.onDebugEvent;
-    var subscription;
+    var stream = service!.onDebugEvent;
+    late var subscription;
     subscription = stream.listen((Event event) {
       if (event.kind == EventKind.kPauseInterrupted) {
         subscription.cancel();
@@ -40,7 +40,7 @@
       }
     });
     await service.streamListen(EventStreams.kDebug);
-    await service.pause(isolateRef.id);
+    await service.pause(isolateRef!.id);
     await completer.future;
     await service.streamCancel(EventStreams.kDebug);
   },
@@ -49,7 +49,7 @@
   (VmService service, IsolateRef isolate) async {
     Completer completer = Completer();
     var stream = service.onDebugEvent;
-    var subscription;
+    late var subscription;
     subscription = stream.listen((Event event) {
       if (event.kind == EventKind.kResume) {
         subscription.cancel();
@@ -66,12 +66,12 @@
   (VmService service, IsolateRef isolateRef) async {
     Isolate isolate = await service.getIsolate(isolateRef.id);
     final Library rootLib =
-        await service.getObject(isolate.id, isolate.rootLib.id);
+        (await service.getObject(isolate.id, isolate.rootLib!.id)) as Library;
 
     // Set up a listener to wait for breakpoint events.
     Completer completer = Completer();
     var stream = service.onDebugEvent;
-    var subscription;
+    late var subscription;
     subscription = stream.listen((Event event) {
       if (event.kind == EventKind.kPauseBreakpoint) {
         print('Breakpoint reached');
@@ -80,8 +80,8 @@
       }
     });
     await service.streamListen(EventStreams.kDebug);
-    final Script script =
-        await service.getObject(isolate.id, rootLib.scripts.first.id);
+    final Script script = (await service.getObject(
+        isolate.id, rootLib.scripts.first.id)) as Script;
     // Add the breakpoint.
     final Breakpoint bpt =
         await service.addBreakpoint(isolate.id, script.id, 16);
@@ -100,10 +100,10 @@
     final stack = await service.getStack(isolateRef.id);
     expect(stack.frames.length, greaterThanOrEqualTo(1));
 
-    Script script = await service.getObject(
-        isolateRef.id, stack.frames[0].location.script.id);
+    Script script = (await service.getObject(
+        isolateRef.id, stack.frames[0].location!.script.id)) as Script;
     expect(script.uri, endsWith('debugging_test.dart'));
-    expect(script.getLineNumberFromTokenPos(stack.frames[0].location.tokenPos),
+    expect(script.getLineNumberFromTokenPos(stack.frames[0].location!.tokenPos),
         16);
   },
 
@@ -112,7 +112,7 @@
     // Set up a listener to wait for breakpoint events.
     final completer = Completer();
     var stream = service.onDebugEvent;
-    var subscription;
+    late var subscription;
     subscription = stream.listen((Event event) {
       if (event.kind == EventKind.kPauseBreakpoint) {
         print('Breakpoint reached');
@@ -131,10 +131,10 @@
     final stack = await service.getStack(isolateRef.id);
     expect(stack.frames.length, greaterThanOrEqualTo(1));
 
-    final Script script = await service.getObject(
-        isolateRef.id, stack.frames[0].location.script.id);
+    final Script script = (await service.getObject(
+        isolateRef.id, stack.frames[0].location!.script.id)) as Script;
     expect(script.uri, endsWith('debugging_test.dart'));
-    expect(script.getLineNumberFromTokenPos(stack.frames[0].location.tokenPos),
+    expect(script.getLineNumberFromTokenPos(stack.frames[0].location!.tokenPos),
         17);
   },
 // Remove breakpoint
@@ -142,7 +142,7 @@
     // Set up a listener to wait for breakpoint events.
     final completer = Completer();
     var stream = service.onDebugEvent;
-    var subscription;
+    late var subscription;
     subscription = stream.listen((Event event) async {
       if (event.kind == EventKind.kBreakpointRemoved) {
         print('Breakpoint removed');
@@ -165,7 +165,7 @@
   (VmService service, IsolateRef isolate) async {
     final completer = Completer();
     var stream = service.onDebugEvent;
-    var subscription;
+    late var subscription;
     subscription = stream.listen((Event event) {
       if (event.kind == EventKind.kResume) {
         subscription.cancel();
@@ -181,7 +181,7 @@
     // Set up a listener to wait for breakpoint events.
     final completer = Completer();
     var stream = service.onDebugEvent;
-    var subscription;
+    late var subscription;
     subscription = stream.listen((Event event) {
       if (event.kind == EventKind.kPauseBreakpoint) {
         print('Breakpoint reached');
@@ -192,7 +192,7 @@
 
     await service.streamListen(EventStreams.kDebug);
     final Library rootLib =
-        await service.getObject(isolate.id, isolate.rootLib.id);
+        (await service.getObject(isolate.id, isolate.rootLib!.id)) as Library;
 
     // Find a specific function.
     final FuncRef function =
@@ -202,7 +202,7 @@
     // Add the breakpoint at function entry
     final bpt = await service.addBreakpointAtEntry(isolate.id, function.id);
     final Script script =
-        await service.getObject(isolate.id, bpt.location.script.id);
+        (await service.getObject(isolate.id, bpt.location.script.id)) as Script;
     expect(script.uri, endsWith('debugging_test.dart'));
     expect(script.getLineNumberFromTokenPos(bpt.location.tokenPos), 14);
 
@@ -217,10 +217,10 @@
     final stack = await service.getStack(isolateRef.id);
     expect(stack.frames.length, greaterThanOrEqualTo(1));
 
-    final Script script = await service.getObject(
-        isolateRef.id, stack.frames[0].location.script.id);
+    final Script script = (await service.getObject(
+        isolateRef.id, stack.frames[0].location!.script.id)) as Script;
     expect(script.uri, endsWith('debugging_test.dart'));
-    expect(script.getLineNumberFromTokenPos(stack.frames[0].location.tokenPos),
+    expect(script.getLineNumberFromTokenPos(stack.frames[0].location!.tokenPos),
         14);
   },
 ];
diff --git a/pkg/vm_service/test/eval_test.dart b/pkg/vm_service/test/eval_test.dart
index ba30330..031b1a9e 100644
--- a/pkg/vm_service/test/eval_test.dart
+++ b/pkg/vm_service/test/eval_test.dart
@@ -44,12 +44,12 @@
 
     // Make sure we are in the right place.
     expect(stack.frames.length, greaterThanOrEqualTo(2));
-    expect(stack.frames[0].function.name, 'method');
-    expect((stack.frames[0].function.owner as ClassRef).name, 'MyClass');
+    expect(stack.frames[0].function!.name, 'method');
+    expect((stack.frames[0].function!.owner as ClassRef).name, 'MyClass');
 
-    final LibraryRef lib = isolate.rootLib;
-    final ClassRef cls = stack.frames[0].function.owner;
-    final InstanceRef instance = stack.frames[0].vars[0].value;
+    final LibraryRef lib = isolate.rootLib!;
+    final ClassRef cls = stack.frames[0].function!.owner;
+    final InstanceRef instance = stack.frames[0].vars![0].value;
 
     dynamic result =
         await service.evaluate(isolate.id, lib.id, 'globalVar + 5');
@@ -80,13 +80,13 @@
 
     // Make sure we are in the right place.
     expect(stack.frames.length, greaterThanOrEqualTo(2));
-    expect(stack.frames[0].function.name, 'foo');
-    expect((stack.frames[0].function.owner as ClassRef).name, '_MyClass');
+    expect(stack.frames[0].function!.name, 'foo');
+    expect((stack.frames[0].function!.owner as ClassRef).name, '_MyClass');
 
-    final ClassRef cls = stack.frames[0].function.owner;
+    final ClassRef cls = stack.frames[0].function!.owner;
 
     final InstanceRef result =
-        await service.evaluate(isolate.id, cls.id, "1+1");
+        await service.evaluate(isolate.id, cls.id, "1+1") as InstanceRef;
     print(result);
     expect(result.valueAsString, "2");
   }
diff --git a/pkg/vm_service/test/evaluate_with_scope_test.dart b/pkg/vm_service/test/evaluate_with_scope_test.dart
index 8dfd4d4..4d04f7c 100644
--- a/pkg/vm_service/test/evaluate_with_scope_test.dart
+++ b/pkg/vm_service/test/evaluate_with_scope_test.dart
@@ -6,8 +6,8 @@
 import 'package:test/test.dart';
 import 'common/test_helper.dart';
 
-int thing1;
-int thing2;
+int? thing1;
+int? thing2;
 
 testeeMain() {
   thing1 = 3;
@@ -20,15 +20,18 @@
 final tests = <IsolateTest>[
   (VmService service, IsolateRef isolateRef) async {
     final isolate = await service.getIsolate(isolateRef.id);
-    final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
+    final Library lib =
+        (await service.getObject(isolate.id, isolate.rootLib!.id)) as Library;
 
-    final Field field1 = await service.getObject(
-        isolate.id, lib.variables.singleWhere((v) => v.name == 'thing1').id);
-    final thing1 = (await service.getObject(isolate.id, field1.staticValue.id));
+    final Field field1 = (await service.getObject(isolate.id,
+        lib.variables.singleWhere((v) => v.name == 'thing1').id)) as Field;
+    final thing1 =
+        (await service.getObject(isolate.id, field1.staticValue!.id));
 
-    final Field field2 = await service.getObject(
-        isolate.id, lib.variables.singleWhere((v) => v.name == 'thing2').id);
-    final thing2 = (await service.getObject(isolate.id, field2.staticValue.id));
+    final Field field2 = (await service.getObject(isolate.id,
+        lib.variables.singleWhere((v) => v.name == 'thing2').id)) as Field;
+    final thing2 =
+        (await service.getObject(isolate.id, field2.staticValue!.id));
 
     var result = await evaluate(service, isolate, lib, thing1, thing2);
     expect(result.valueAsString, equals('7'));
diff --git a/pkg/vm_service/test/get_cpu_samples_rpc_test.dart b/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
index 8b9b143..321a01c 100644
--- a/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
+++ b/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
@@ -47,7 +47,7 @@
 }
 
 var tests = <IsolateTest>[
-  (VmService service, IsolateRef i) => checkSamples(service, i),
+  ((VmService service, IsolateRef i) => checkSamples(service, i)),
 ];
 
 var vmArgs = [
diff --git a/pkg/vm_service/test/get_flag_list_rpc_test.dart b/pkg/vm_service/test/get_flag_list_rpc_test.dart
index 8b6c337..791687d 100644
--- a/pkg/vm_service/test/get_flag_list_rpc_test.dart
+++ b/pkg/vm_service/test/get_flag_list_rpc_test.dart
@@ -22,14 +22,15 @@
 var tests = <VMTest>[
   // Modify a flag which does not exist.
   (VmService service) async {
-    final Error result = await service.setFlag('does_not_exist', 'true');
+    final Error result =
+        (await service.setFlag('does_not_exist', 'true')) as Error;
     expect(result.message, 'Cannot set flag: flag not found');
   },
 
   // Modify a flag with the wrong value type.
   (VmService service) async {
-    final Error result =
-        await service.setFlag('pause_isolates_on_start', 'not-boolean');
+    final Error result = (await service.setFlag(
+        'pause_isolates_on_start', 'not-boolean')) as Error;
     expect(result.message, equals('Cannot set flag: invalid value'));
   },
 
@@ -41,7 +42,7 @@
 
   // Modify a flag which cannot be set at runtime.
   (VmService service) async {
-    final Error result = await service.setFlag('random_seed', '42');
+    final Error result = (await service.setFlag('random_seed', '42')) as Error;
     expect(result.message, 'Cannot set flag: cannot change at runtime');
   },
 
@@ -52,7 +53,7 @@
     expect(await getFlagValue(service, kProfilePeriod), '1000');
     final completer = Completer();
     final stream = await service.onVMEvent;
-    var subscription;
+    late var subscription;
     subscription = stream.listen((Event event) {
       print(event);
       if (event.kind == EventKind.kVMFlagUpdate) {
diff --git a/pkg/vm_service/test/get_isolate_group_memory_usage.dart b/pkg/vm_service/test/get_isolate_group_memory_usage.dart
index e6323a1..c59608a 100644
--- a/pkg/vm_service/test/get_isolate_group_memory_usage.dart
+++ b/pkg/vm_service/test/get_isolate_group_memory_usage.dart
@@ -17,7 +17,7 @@
     expect(result.externalUsage, isNonNegative);
   },
   (VmService service) async {
-    bool caughtException;
+    bool? caughtException;
     try {
       await service.getMemoryUsage('badid');
       fail('Unreachable');
diff --git a/pkg/vm_service/test/get_isolate_rpc_test.dart b/pkg/vm_service/test/get_isolate_rpc_test.dart
index 6df4ec0..bb7dfed 100644
--- a/pkg/vm_service/test/get_isolate_rpc_test.dart
+++ b/pkg/vm_service/test/get_isolate_rpc_test.dart
@@ -16,7 +16,7 @@
     expect(result.isolateFlags, isNotNull);
     expect(result.isolateFlags.length, isPositive);
     expect(result.isSystemIsolate, isFalse);
-    expect(result.json['_originNumber'], result.number);
+    expect(result.json!['_originNumber'], result.number);
     expect(result.startTime, isPositive);
     expect(result.livePorts, isPositive);
     expect(result.pauseOnExit, isFalse);
@@ -26,12 +26,12 @@
     expect(result.libraries.length, isPositive);
     expect(result.libraries[0], isNotNull);
     expect(result.breakpoints.length, isZero);
-    expect(result.json['_heaps']['new']['type'], 'HeapSpace');
-    expect(result.json['_heaps']['old']['type'], 'HeapSpace');
+    expect(result.json!['_heaps']['new']['type'], 'HeapSpace');
+    expect(result.json!['_heaps']['old']['type'], 'HeapSpace');
   },
 
   (VmService service) async {
-    bool caughtException;
+    bool caughtException = false;
     try {
       await service.getIsolate('badid');
       expect(false, isTrue, reason: 'Unreachable');
diff --git a/pkg/vm_service/test/get_memory_usage.dart b/pkg/vm_service/test/get_memory_usage.dart
index 76cac44..b6adbef 100644
--- a/pkg/vm_service/test/get_memory_usage.dart
+++ b/pkg/vm_service/test/get_memory_usage.dart
@@ -16,7 +16,7 @@
     expect(result.externalUsage, isPositive);
   },
   (VmService service) async {
-    bool caughtException;
+    bool? caughtException;
     try {
       await service.getMemoryUsage('badid');
       fail('Unreachable');
diff --git a/pkg/vm_service/test/heap_snapshot_graph_test.dart b/pkg/vm_service/test/heap_snapshot_graph_test.dart
index 7b035cc..b9fbe10 100644
--- a/pkg/vm_service/test/heap_snapshot_graph_test.dart
+++ b/pkg/vm_service/test/heap_snapshot_graph_test.dart
@@ -13,9 +13,9 @@
   dynamic right;
 }
 
-Foo r;
+late Foo r;
 
-List lst;
+late List lst;
 
 void script() {
   // Create 3 instances of Foo, with out-degrees
diff --git a/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart b/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
index 10157d5..a4f88f7 100644
--- a/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
+++ b/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
@@ -25,11 +25,11 @@
     {bool useSetter = true}) async {
   final completer = Completer<void>();
   final isolateId = isolateRef.id;
-  StreamSubscription sub;
+  late StreamSubscription sub;
   sub = service.onExtensionEvent.listen((event) {
     expect(event.extensionKind, 'HttpTimelineLoggingStateChange');
-    expect(event.extensionData.data['isolateId'], isolateRef.id);
-    expect(event.extensionData.data['enabled'], state);
+    expect(event.extensionData!.data['isolateId'], isolateRef.id);
+    expect(event.extensionData!.data['enabled'], state);
     sub.cancel();
     completer.complete();
   });
@@ -49,12 +49,12 @@
   (VmService service, IsolateRef isolateRef) async {
     final isolate = await service.getIsolate(isolateRef.id);
     // Ensure all HTTP service extensions are registered.
-    expect(isolate.extensionRPCs.length, greaterThanOrEqualTo(2));
+    expect(isolate.extensionRPCs!.length, greaterThanOrEqualTo(2));
     expect(
-        isolate.extensionRPCs.contains(kGetHttpEnableTimelineLogging), isTrue);
+        isolate.extensionRPCs!.contains(kGetHttpEnableTimelineLogging), isTrue);
     expect(
-        isolate.extensionRPCs.contains(kSetHttpEnableTimelineLogging), isTrue);
-    expect(isolate.extensionRPCs.contains(kHttpEnableTimelineLogging), isTrue);
+        isolate.extensionRPCs!.contains(kSetHttpEnableTimelineLogging), isTrue);
+    expect(isolate.extensionRPCs!.contains(kHttpEnableTimelineLogging), isTrue);
   },
   (VmService service, IsolateRef isolateRef) async {
     final isolateId = isolateRef.id;
diff --git a/pkg/vm_service/test/invoke_test.dart b/pkg/vm_service/test/invoke_test.dart
index 651e39e..47d7f8c 100644
--- a/pkg/vm_service/test/invoke_test.dart
+++ b/pkg/vm_service/test/invoke_test.dart
@@ -31,19 +31,21 @@
   hasStoppedAtBreakpoint,
   (VmService service, IsolateRef isolateRef) async {
     final isolate = await service.getIsolate(isolateRef.id);
-    final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
+    final Library lib =
+        await service.getObject(isolate.id, isolate.rootLib!.id) as Library;
     final cls = lib.classes.singleWhere((cls) => cls.name == "Klass");
     FieldRef fieldRef =
         lib.variables.singleWhere((field) => field.name == "instance");
-    Field field = await service.getObject(isolate.id, fieldRef.id);
-    final instance = await service.getObject(isolate.id, field.staticValue.id);
+    Field field = await service.getObject(isolate.id, fieldRef.id) as Field;
+    final instance = await service.getObject(isolate.id, field.staticValue!.id);
 
     fieldRef = lib.variables.singleWhere((field) => field.name == "apple");
-    field = await service.getObject(isolate.id, fieldRef.id);
-    final apple = await service.getObject(isolate.id, field.staticValue.id);
+    field = await service.getObject(isolate.id, fieldRef.id) as Field;
+    final apple = await service.getObject(isolate.id, field.staticValue!.id);
     fieldRef = lib.variables.singleWhere((field) => field.name == "banana");
-    field = await service.getObject(isolate.id, fieldRef.id);
-    Instance banana = await service.getObject(isolate.id, field.staticValue.id);
+    field = await service.getObject(isolate.id, fieldRef.id) as Field;
+    Instance banana =
+        await service.getObject(isolate.id, field.staticValue!.id) as Instance;
 
     dynamic result =
         await service.invoke(isolate.id, lib.id, 'libraryFunction', []);
@@ -69,7 +71,7 @@
 
 expectError(func) async {
   dynamic result = await func();
-  expect(result.type == 'Error' || result.type == '@Error', isTrue);
+  expect(result.type == 'Error' || result.type == 'ErrorRef', isTrue);
 }
 
 main([args = const <String>[]]) =>
diff --git a/pkg/vm_service/test/network_profiling_test.dart b/pkg/vm_service/test/network_profiling_test.dart
index d554d81..1463fbe 100644
--- a/pkg/vm_service/test/network_profiling_test.dart
+++ b/pkg/vm_service/test/network_profiling_test.dart
@@ -29,11 +29,11 @@
     {bool useSetter = true}) async {
   final completer = Completer<void>();
   final isolateId = isolateRef.id;
-  StreamSubscription sub;
+  late StreamSubscription sub;
   sub = service.onExtensionEvent.listen((event) {
     expect(event.extensionKind, 'SocketProfilingStateChange');
-    expect(event.extensionData.data['isolateId'], isolateRef.id);
-    expect(event.extensionData.data['enabled'], state);
+    expect(event.extensionData!.data['isolateId'], isolateRef.id);
+    expect(event.extensionData!.data['enabled'], state);
     sub.cancel();
     completer.complete();
   });
@@ -60,7 +60,7 @@
   var socket = await io.Socket.connect(localhost, serverSocket.port);
   socket.write(content);
   await socket.flush();
-  await socket.destroy();
+  socket.destroy();
 
   // rawDatagram
   final doneCompleter = Completer<void>();
@@ -88,13 +88,13 @@
   (VmService service, IsolateRef isolateRef) async {
     final isolate = await service.getIsolate(isolateRef.id);
     // Ensure all network profiling service extensions are registered.
-    expect(isolate.extensionRPCs.length, greaterThanOrEqualTo(5));
-    expect(isolate.extensionRPCs.contains(kClearSocketProfileRPC), isTrue);
-    expect(isolate.extensionRPCs.contains(kGetVersionRPC), isTrue);
-    expect(isolate.extensionRPCs.contains(kPauseSocketProfilingRPC), isTrue);
-    expect(isolate.extensionRPCs.contains(kStartSocketProfilingRPC), isTrue);
-    expect(isolate.extensionRPCs.contains(kPauseSocketProfilingRPC), isTrue);
-    expect(isolate.extensionRPCs.contains(kSocketProfilingEnabledRPC), isTrue);
+    expect(isolate.extensionRPCs!.length, greaterThanOrEqualTo(5));
+    expect(isolate.extensionRPCs!.contains(kClearSocketProfileRPC), isTrue);
+    expect(isolate.extensionRPCs!.contains(kGetVersionRPC), isTrue);
+    expect(isolate.extensionRPCs!.contains(kPauseSocketProfilingRPC), isTrue);
+    expect(isolate.extensionRPCs!.contains(kStartSocketProfilingRPC), isTrue);
+    expect(isolate.extensionRPCs!.contains(kPauseSocketProfilingRPC), isTrue);
+    expect(isolate.extensionRPCs!.contains(kSocketProfilingEnabledRPC), isTrue);
   },
 
   // Test getSocketProfiler
diff --git a/pkg/vm_service/test/process_service_test.dart b/pkg/vm_service/test/process_service_test.dart
index a47359a..d8f63ea 100644
--- a/pkg/vm_service/test/process_service_test.dart
+++ b/pkg/vm_service/test/process_service_test.dart
@@ -24,19 +24,19 @@
     '--pause_isolates_on_start',
     io.Platform.script.toFilePath(),
   ];
-  io.Process process1;
-  io.Process process2;
-  io.Process process3;
+  io.Process? process1;
+  io.Process? process2;
+  io.Process? process3;
 
   void closeDown() {
     if (process1 != null) {
-      process1.kill();
+      process1!.kill();
     }
     if (process2 != null) {
-      process2.kill();
+      process2!.kill();
     }
     if (process3 != null) {
-      process3.kill();
+      process3!.kill();
     }
     dir.deleteSync(recursive: true);
   }
@@ -70,14 +70,14 @@
 
     final result = jsonEncode({
       'type': 'foobar',
-      'pids': [process1.pid, process2.pid, process3.pid]
+      'pids': [process1!.pid, process2!.pid, process3!.pid]
     });
     return Future.value(ServiceExtensionResponse.result(result));
   }
 
   Future<ServiceExtensionResponse> closeStdin(ignored_a, ignored_b) {
-    process3.stdin.close();
-    return process3.exitCode.then<ServiceExtensionResponse>((int exit) {
+    process3!.stdin.close();
+    return process3!.exitCode.then<ServiceExtensionResponse>((int exit) {
       final result = jsonEncode({'type': 'foobar'});
       return ServiceExtensionResponse.result(result);
     });
@@ -105,7 +105,7 @@
       );
 
       expect(first.name, io.Platform.executable);
-      expect(first.pid, equals(setup.json['pids'][0]));
+      expect(first.pid, equals(setup.json!['pids']![0]));
       expect(first.arguments.contains('foobar'), isFalse);
       expect(first.startedAt, greaterThan(0));
 
@@ -115,7 +115,7 @@
       );
 
       expect(second.name, io.Platform.executable);
-      expect(second.pid, equals(setup.json['pids'][1]));
+      expect(second.pid, equals(setup.json!['pids']![1]));
       expect(second.arguments.contains('foobar'), isTrue);
       expect(second.pid != first.pid, isTrue);
       expect(second.startedAt, greaterThan(0));
@@ -127,7 +127,7 @@
       );
 
       expect(third.name, dartJITBinary);
-      expect(third.pid, equals(setup.json['pids'][2]));
+      expect(third.pid, equals(setup.json!['pids']![2]));
       expect(third.pid != first.pid, isTrue);
       expect(third.pid != second.pid, isTrue);
       expect(third.startedAt, greaterThanOrEqualTo(second.startedAt));
diff --git a/pkg/vm_service/test/server_test.dart b/pkg/vm_service/test/server_test.dart
index 2362c93..97b0aed 100644
--- a/pkg/vm_service/test/server_test.dart
+++ b/pkg/vm_service/test/server_test.dart
@@ -2,6 +2,8 @@
 // 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.10
+
 @TestOn('vm')
 import 'dart:async';
 import 'dart:convert';
@@ -110,7 +112,7 @@
       test('with no params or isolateId', () {
         var extension = 'ext.cool';
         var request = rpcRequest(extension, params: null);
-        var response = Response(type: '')..json = {"hello": "world"};
+        var response = Response()..json = {"hello": "world"};
         when(serviceMock.callServiceExtension(
           extension,
           isolateId: argThat(isNull, named: 'isolateId'),
@@ -127,7 +129,7 @@
       test('with isolateId and no other params', () {
         var extension = 'ext.cool';
         var request = rpcRequest(extension, params: {'isolateId': '1'});
-        var response = Response(type: '')..json = {"hello": "world"};
+        var response = Response()..json = {"hello": "world"};
         when(serviceMock.callServiceExtension(
           extension,
           isolateId: argThat(equals('1'), named: 'isolateId'),
@@ -145,7 +147,7 @@
         var extension = 'ext.cool';
         var params = {'cool': 'option'};
         var request = rpcRequest(extension, params: params);
-        var response = Response(type: '')..json = {"hello": "world"};
+        var response = Response()..json = {"hello": "world"};
         when(serviceMock.callServiceExtension(
           extension,
           isolateId: argThat(isNull, named: 'isolateId'),
@@ -164,7 +166,7 @@
         var params = {'cool': 'option'};
         var request =
             rpcRequest(extension, params: Map.of(params)..['isolateId'] = '1');
-        var response = Response(type: '')..json = {"hello": "world"};
+        var response = Response()..json = {"hello": "world"};
         when(serviceMock.callServiceExtension(
           extension,
           isolateId: argThat(equals("1"), named: 'isolateId'),
@@ -214,7 +216,7 @@
         when(serviceMock.streamListen(streamId))
             .thenAnswer((_) => Future.value(response));
         requestsController.add(request);
-        await expect(responseQueue, emitsThrough(rpcResponse(response)));
+        await expectLater(responseQueue, emitsThrough(rpcResponse(response)));
 
         eventController = serviceMock.streamControllers[streamId];
 
@@ -229,7 +231,7 @@
           )
         ];
         events.forEach(eventController.add);
-        await expect(
+        await expectLater(
             responseQueue,
             emitsInOrder(
                 events.map((event) => streamNotifyResponse(streamId, event))));
@@ -241,7 +243,7 @@
         when(serviceMock.streamListen(streamId))
             .thenAnswer((_) => Future.value(response));
         requestsController.add(request);
-        await expect(responseQueue, emitsThrough(rpcResponse(response)));
+        await expectLater(responseQueue, emitsThrough(rpcResponse(response)));
 
         var nextEvent = Event(
           kind: EventKind.kIsolateReload,
@@ -329,7 +331,7 @@
             rpcRequest('streamListen', params: {'streamId': serviceStream}));
         requestsController
             .add(rpcRequest('registerService', params: {'service': serviceId}));
-        await expect(
+        await expectLater(
             responsesController.stream
                 .map((Map response) => stripEventTimestamp(response)),
             emitsThrough(serviceRegisteredEvent));
@@ -343,8 +345,12 @@
           responsesController2.close();
         });
 
-        VmServerConnection(requestsController2.stream,
-            responsesController2.sink, serviceRegistry, null);
+        VmServerConnection(
+          requestsController2.stream,
+          responsesController2.sink,
+          serviceRegistry,
+          VmService(Stream.empty(), (String _) => null),
+        );
 
         expect(
             responsesController2.stream
@@ -367,8 +373,12 @@
         var requestsController3 = StreamController<Map<String, Object>>();
         var responsesController3 = StreamController<Map<String, Object>>();
 
-        VmServerConnection(requestsController3.stream,
-            responsesController3.sink, serviceRegistry, null);
+        VmServerConnection(
+          requestsController3.stream,
+          responsesController3.sink,
+          serviceRegistry,
+          VmService(Stream.empty(), (String _) => null),
+        );
         expect(
             responsesController3.stream,
             neverEmits(
@@ -402,13 +412,13 @@
           clientInputController.sink, serviceRegistry, serviceMock);
 
       var requestParams = {'foo': 'bar'};
-      var expectedResponse = Response(type: '')..json = {'zap': 'zip'};
-      await client.registerService(serviceId, null);
+      var expectedResponse = Response()..json = {'zap': 'zip'};
+      await client.registerService(serviceId, 'service');
       // Duplicate registrations should fail.
-      expect(client.registerService(serviceId, null),
+      expect(client.registerService(serviceId, 'service'),
           throwsA(const TypeMatcher<RPCError>()));
 
-      await client.registerServiceCallback(serviceId, (request) async {
+      client.registerServiceCallback(serviceId, (request) async {
         expect(request, equals(requestParams));
         return {'result': expectedResponse.toJson()};
       });
@@ -424,7 +434,7 @@
       // This should complete as well.
       await clientConnection.done;
 
-      var mockResponse = Response(type: '')..json = {'mock': 'response'};
+      var mockResponse = Response()..json = {'mock': 'response'};
       when(serviceMock.callServiceExtension(serviceId,
               args: argThat(equals(requestParams), named: 'args'),
               isolateId: argThat(isNull, named: 'isolateId')))
@@ -490,7 +500,7 @@
       response['params'].containsKey('event')) {
     response['params']['event']['timestamp'] = 0;
   }
-  return response;
+  return response as Map<String, Object>;
 }
 
 class MockVmService extends Mock implements VmServiceInterface {
diff --git a/pkg/vm_service/tool/common/generate_common.dart b/pkg/vm_service/tool/common/generate_common.dart
index f250c55..d91e730 100644
--- a/pkg/vm_service/tool/common/generate_common.dart
+++ b/pkg/vm_service/tool/common/generate_common.dart
@@ -4,6 +4,9 @@
 
 library generate_vm_service_common;
 
+// TODO(bkonyi): remove once markdown and pub_semver deps are updated to null
+// safety for the SDK.
+// ignore_for_file: import_of_legacy_library_into_null_safe
 import 'package:markdown/markdown.dart';
 import 'package:pub_semver/pub_semver.dart';
 
@@ -19,9 +22,9 @@
     final RegExp regex = RegExp(r'[\d.]+');
 
     // Extract version from header: `# Dart VM Service Protocol 2.0`.
-    Element node = nodes.firstWhere((n) => isH1(n));
-    Text text = node.children[0];
-    Match match = regex.firstMatch(text.text);
+    Element node = nodes.firstWhere((n) => isH1(n)) as Element;
+    Text text = node.children[0] as Text;
+    Match? match = regex.firstMatch(text.text);
     if (match == null) throw 'Unable to locate service protocol version';
 
     // Append a `.0`.
diff --git a/pkg/vm_service/tool/common/parser.dart b/pkg/vm_service/tool/common/parser.dart
index 3a58340..08d3709 100644
--- a/pkg/vm_service/tool/common/parser.dart
+++ b/pkg/vm_service/tool/common/parser.dart
@@ -7,21 +7,21 @@
 class Token {
   static final RegExp _alpha = RegExp(r'^[0-9a-zA-Z_\-@]+$');
 
-  final String text;
-  Token next;
+  final String? text;
+  Token? next;
 
   Token(this.text);
 
   bool get eof => text == null;
 
   bool get isName {
-    if (text == null || text.isEmpty) return false;
-    return _alpha.hasMatch(text);
+    if (text == null || text!.isEmpty) return false;
+    return _alpha.hasMatch(text!);
   }
 
-  bool get isComment => text != null && text.startsWith('//');
+  bool get isComment => text != null && text!.startsWith('//');
 
-  String toString() => text == null ? 'EOF' : text;
+  String toString() => text == null ? 'EOF' : text!;
 }
 
 class Tokenizer {
@@ -30,12 +30,12 @@
   static final whitespace = ' \n\t\r';
 
   String text;
-  Token _head;
-  Token _last;
+  Token? _head;
+  Token? _last;
 
   Tokenizer(this.text);
 
-  Token tokenize() {
+  Token? tokenize() {
     _emit(null);
 
     for (int i = 0; i < text.length; i++) {
@@ -63,15 +63,15 @@
 
     _emit(null);
 
-    _head = _head.next;
+    _head = _head!.next;
 
     return _head;
   }
 
-  void _emit(String value) {
+  void _emit(String? value) {
     Token token = Token(value);
     if (_head == null) _head = token;
-    if (_last != null) _last.next = token;
+    if (_last != null) _last!.next = token;
     _last = token;
   }
 
@@ -83,12 +83,12 @@
   String toString() {
     StringBuffer buf = StringBuffer();
 
-    Token t = _head;
+    Token t = _head!;
 
     buf.write('[${t}]\n');
 
     while (!t.eof) {
-      t = t.next;
+      t = t.next!;
       buf.write('[${t}]\n');
     }
 
@@ -97,20 +97,20 @@
 }
 
 abstract class Parser {
-  final Token startToken;
+  final Token? startToken;
 
-  Token current;
+  Token? current;
 
   Parser(this.startToken);
 
   Token expect(String text) {
-    Token t = advance();
+    Token t = advance()!;
     if (text != t.text) fail('expected ${text}, got ${t}');
     return t;
   }
 
   bool consume(String text) {
-    if (peek().text == text) {
+    if (peek()!.text == text) {
       advance();
       return true;
     } else {
@@ -118,31 +118,34 @@
     }
   }
 
-  Token peek() =>
-      current == null ? startToken : current.eof ? current : current.next;
+  Token? peek() => current == null
+      ? startToken
+      : current!.eof
+          ? current
+          : current!.next;
 
   Token expectName() {
-    Token t = advance();
+    Token t = advance()!;
     if (!t.isName) fail('expected name token, got ${t}');
     return t;
   }
 
-  Token advance() {
+  Token? advance() {
     if (current == null) {
       current = startToken;
-    } else if (!current.eof) {
-      current = current.next;
+    } else if (!current!.eof) {
+      current = current!.next;
     }
 
     return current;
   }
 
-  String collectComments() {
+  String? collectComments() {
     StringBuffer buf = StringBuffer();
 
-    while (peek().isComment) {
-      Token t = advance();
-      String str = t.text.substring(2);
+    while (peek()!.isComment) {
+      Token t = advance()!;
+      String str = t.text!.substring(2);
 
       if (str.startsWith(' ')) str = str.substring(1);
 
diff --git a/pkg/vm_service/tool/common/src_gen_common.dart b/pkg/vm_service/tool/common/src_gen_common.dart
index cb5a9fd..4fd8313 100644
--- a/pkg/vm_service/tool/common/src_gen_common.dart
+++ b/pkg/vm_service/tool/common/src_gen_common.dart
@@ -4,6 +4,9 @@
 
 library src_gen_common;
 
+// TODO(bkonyi): remove once markdown and pub_semver deps are updated to null
+// safety for the SDK.
+// ignore_for_file: import_of_legacy_library_into_null_safe
 import 'package:markdown/markdown.dart';
 
 const int RUNE_SPACE = 32;
@@ -36,7 +39,7 @@
 String lowerTitleCase(String str) =>
     str.substring(0, 1).toLowerCase() + str.substring(1);
 
-String joinLast(Iterable<String> strs, String join, [String last]) {
+String joinLast(Iterable<String> strs, String join, [String? last]) {
   if (strs.isEmpty) return '';
   List list = strs.toList();
   if (list.length == 1) return list.first;
diff --git a/pkg/vm_service/tool/dart/generate_dart.dart b/pkg/vm_service/tool/dart/generate_dart.dart
index e8dabfe..95a57cb 100644
--- a/pkg/vm_service/tool/dart/generate_dart.dart
+++ b/pkg/vm_service/tool/dart/generate_dart.dart
@@ -4,6 +4,9 @@
 
 library generate_vm_service_dart;
 
+// TODO(bkonyi): remove once markdown and pub_semver deps are updated to null
+// safety for the SDK.
+// ignore_for_file: import_of_legacy_library_into_null_safe
 import 'package:markdown/markdown.dart';
 
 import '../common/generate_common.dart';
@@ -13,9 +16,9 @@
 
 export 'src_gen_dart.dart' show DartGenerator;
 
-Api api;
+late Api api;
 
-String _coerceRefType(String typeName) {
+String? _coerceRefType(String? typeName) {
   if (typeName == 'Object') typeName = 'Obj';
   if (typeName == '@Object') typeName = 'ObjRef';
   if (typeName == 'Null') typeName = 'NullVal';
@@ -23,7 +26,7 @@
   if (typeName == 'Function') typeName = 'Func';
   if (typeName == '@Function') typeName = 'FuncRef';
 
-  if (typeName.startsWith('@')) typeName = typeName.substring(1) + 'Ref';
+  if (typeName!.startsWith('@')) typeName = typeName.substring(1) + 'Ref';
 
   if (typeName == 'string') typeName = 'String';
   if (typeName == 'map') typeName = 'Map';
@@ -32,7 +35,7 @@
 }
 
 String _typeRefListToString(List<TypeRef> types) =>
-    'const [' + types.map((e) => "'" + e.name + "'").join(',') + ']';
+    'const [' + types.map((e) => "'" + e.name! + "'").join(',') + ']';
 
 final String _headerCode = r'''
 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
@@ -49,8 +52,6 @@
 import 'dart:convert' show base64, jsonDecode, jsonEncode, utf8;
 import 'dart:typed_data';
 
-import 'package:meta/meta.dart';
-
 import 'service_extension_registry.dart';
 
 export 'service_extension_registry.dart' show ServiceExtensionRegistry;
@@ -69,8 +70,8 @@
   /// Call an arbitrary service protocol method. This allows clients to call
   /// methods not explicitly exposed by this library.
   Future<Response> callMethod(String method, {
-    String isolateId,
-    Map args
+    String? isolateId,
+    Map<String, dynamic>? args
   }) {
     return callServiceExtension(method, isolateId: isolateId, args: args);
   }
@@ -80,13 +81,13 @@
   /// See https://api.dart.dev/stable/dart-developer/dart-developer-library.html.
   @override
   Future<Response> callServiceExtension(String method, {
-    String isolateId,
-    Map args
+    String? isolateId,
+    Map<String, dynamic>? args
   }) {
     if (args == null && isolateId == null) {
       return _call(method);
     } else if (args == null) {
-      return _call(method, {'isolateId': isolateId});
+      return _call(method, {'isolateId': isolateId!});
     } else {
       args = Map.from(args);
       if (isolateId != null) {
@@ -109,7 +110,7 @@
     });
     _completers.clear();
     if (_disposeHandler != null) {
-      await _disposeHandler();
+      await _disposeHandler!();
     }
     if (!_onDoneCompleter.isCompleted) {
       _onDoneCompleter.complete();
@@ -162,22 +163,21 @@
         bytes.buffer, bytes.offsetInBytes + metaOffset, metaLength));
     final data = ByteData.view(
         bytes.buffer, bytes.offsetInBytes + dataOffset, dataLength);
-    dynamic map = jsonDecode(meta);
-    if (map != null && map['method'] == 'streamNotify') {
+    dynamic map = jsonDecode(meta)!;
+    if (map['method'] == 'streamNotify') {
       String streamId = map['params']['streamId'];
       Map event = map['params']['event'];
       event['data'] = data;
       _getEventController(streamId)
-          .add(createServiceObject(event, const ['Event']));
+          .add(createServiceObject(event, const ['Event'])! as Event);
     }
   }
 
   void _processMessageStr(String message) {
-    var json;
+    late Map<String, dynamic> json;
     try {
       _onReceive.add(message);
-
-      json = jsonDecode(message);
+      json = jsonDecode(message)!;
     } catch (e, s) {
       _log.severe('unable to decode message: ${message}, ${e}\n${s}');
       return;
@@ -199,9 +199,9 @@
   }
 
   void _processResponse(Map<String, dynamic> json) {
-    Completer completer = _completers.remove(json['id']);
-    String methodName = _methodCalls.remove(json['id']);
-    List<String> returnTypes = _methodReturnTypes[methodName];
+    Completer? completer = _completers.remove(json['id']);
+    String methodName = _methodCalls.remove(json['id'])!;
+    List<String> returnTypes = _methodReturnTypes[methodName] ?? [];
     if (completer == null) {
       _log.severe('unmatched request response: ${jsonEncode(json)}');
     } else if (json['error'] != null) {
@@ -230,24 +230,25 @@
 
   Future _processNotification(Map<String, dynamic> json) async {
     final String method = json['method'];
-    final Map params = json['params'] ?? <String, dynamic>{};
+    final Map<String, dynamic> params = json['params'] ?? <String, dynamic>{};
     if (method == 'streamNotify') {
       String streamId = params['streamId'];
-      _getEventController(streamId).add(createServiceObject(params['event'], const ['Event']));
+      _getEventController(streamId).add(createServiceObject(params['event'], const ['Event'])! as Event);
     } else {
       await _routeRequest(method, params);
     }
   }
 
   Future<Map> _routeRequest(String method, Map<String, dynamic> params) async{
-    if (!_services.containsKey(method)) {
+    final service = _services[method];
+    if (service == null) {
       RPCError error = RPCError(
           method, RPCError.kMethodNotFound, 'method not found \'$method\'');
       return {'error': error.toMap()};
     }
 
     try {
-      return await _services[method](params);
+      return await service(params);
     } catch (e, st) {
       RPCError error = RPCError.withDetails(
         method, RPCError.kServerError, '$e', details: '$st',);
@@ -281,22 +282,22 @@
     return RPCError(callingMethod, json['code'], json['message'], json['data']);
   }
 
-  final String callingMethod;
+  final String? callingMethod;
   final int code;
   final String message;
-  final Map data;
+  final Map? data;
 
   RPCError(this.callingMethod, this.code, this.message, [this.data]);
 
   RPCError.withDetails(this.callingMethod, this.code, this.message,
-      {Object details})
+      {Object? details})
       : data = details == null ? null : <String, dynamic>{} {
     if (details != null) {
-      data['details'] = details;
+      data!['details'] = details;
     }
   }
 
-  String get details => data == null ? null : data['details'];
+  String? get details => data == null ? null : data!['details'];
 
   /// Return a map representation of this error suitable for converstion to
   /// json.
@@ -326,17 +327,17 @@
   final Sentinel sentinel;
 
   SentinelException.parse(this.callingMethod, Map<String, dynamic> data) :
-    sentinel = Sentinel.parse(data);
+    sentinel = Sentinel.parse(data)!;
 
   String toString() => '$sentinel from ${callingMethod}()';
 }
 
 /// An `ExtensionData` is an arbitrary map that can have any contents.
 class ExtensionData {
-  static ExtensionData parse(Map json) =>
+  static ExtensionData? parse(Map<String, dynamic>? json) =>
       json == null ? null : ExtensionData._fromJson(json);
 
-  final Map data;
+  final Map<String, dynamic> data;
 
   ExtensionData() : data = {};
 
@@ -362,11 +363,11 @@
 ''';
 
 final _registerServiceImpl = '''
-_serviceExtensionRegistry.registerExtension(params['service'], this);
+_serviceExtensionRegistry.registerExtension(params!['service'], this);
 response =  Success();''';
 
 final _streamListenCaseImpl = '''
-var id = params['streamId'];
+var id = params!['streamId'];
 if (_streamSubscriptions.containsKey(id)) {
   throw RPCError.withDetails(
     'streamListen', 103, 'Stream already subscribed',
@@ -390,7 +391,7 @@
 response = Success();''';
 
 final _streamCancelCaseImpl = '''
-var id = params['streamId'];
+var id = params!['streamId'];
 var existing = _streamSubscriptions.remove(id);
 if (existing == null) {
   throw RPCError.withDetails(
@@ -402,22 +403,22 @@
 response = Success();''';
 
 abstract class Member {
-  String get name;
+  String? get name;
 
-  String get docs => null;
+  String? get docs => null;
 
   void generate(DartGenerator gen);
 
   bool get hasDocs => docs != null;
 
-  String toString() => name;
+  String toString() => name!;
 }
 
 class Api extends Member with ApiParseUtil {
-  String serviceVersion;
+  String? serviceVersion;
   List<Method> methods = [];
   List<Enum> enums = [];
-  List<Type> types = [];
+  List<Type?> types = [];
   List<StreamCategory> streamCategories = [];
 
   void parse(List<Node> nodes) {
@@ -427,19 +428,19 @@
     // the pre following it is the definition
     // the optional p following that is the documentation
 
-    String h3Name;
+    String? h3Name;
 
     for (int i = 0; i < nodes.length; i++) {
       Node node = nodes[i];
 
       if (isPre(node) && h3Name != null) {
         String definition = textForCode(node);
-        String docs = '';
+        String? docs = '';
 
         while (i + 1 < nodes.length &&
                 (isPara(nodes[i + 1]) || isBlockquote(nodes[i + 1])) ||
             isList(nodes[i + 1])) {
-          Element p = nodes[++i];
+          Element p = nodes[++i] as Element;
           String str = TextOutputVisitor.printText(p);
           if (!str.contains('|') &&
               !str.contains('``') &&
@@ -449,7 +450,7 @@
           docs = '${docs}\n\n${str}';
         }
 
-        docs = docs.trim();
+        docs = docs!.trim();
         if (docs.isEmpty) docs = null;
 
         _parse(h3Name, definition, docs);
@@ -460,20 +461,20 @@
       }
     }
 
-    for (Type type in types) {
-      type.calculateFieldOverrides();
+    for (Type? type in types) {
+      type!.calculateFieldOverrides();
     }
 
     Method streamListenMethod =
         methods.singleWhere((method) => method.name == 'streamListen');
-    _parseStreamListenDocs(streamListenMethod.docs);
+    _parseStreamListenDocs(streamListenMethod.docs!);
   }
 
   String get name => 'api';
 
-  String get docs => null;
+  String? get docs => null;
 
-  void _parse(String name, String definition, [String docs]) {
+  void _parse(String name, String definition, [String? docs]) {
     name = name.trim();
     definition = definition.trim();
     // clean markdown introduced changes
@@ -518,13 +519,13 @@
 bool _isNullInstance(Map json) => ((json['type'] == '@Instance') &&
                                   (json['kind'] == 'Null'));
 
-Object createServiceObject(dynamic json, List<String> expectedTypes) {
+Object? createServiceObject(dynamic json, List<String> expectedTypes) {
   if (json == null) return null;
 
   if (json is List) {
     return json.map((e) => createServiceObject(e, expectedTypes)).toList();
   } else if (json is Map) {
-    String type = json['type'];
+    String? type = json['type'];
 
     // Not a Response type.
     if (type == null) {
@@ -539,10 +540,11 @@
       // be returned.
       return null;
     }
-    if (_typeFactories[type] == null) {
+    final typeFactory = _typeFactories[type];
+    if (typeFactory == null) {
       return null;
     } else {
-      return _typeFactories[type](json);
+      return typeFactory(json);
     }
   } else {
     // Handle simple types.
@@ -566,7 +568,7 @@
   }
 }
 
-void _setIfNotNull(Map<String, Object> json, String key, Object value) {
+void _setIfNotNull(Map<String, dynamic> json, String key, Object? value) {
   if (value == null) return;
   json[key] = value;
 }
@@ -588,8 +590,8 @@
 ''');
     gen.writeln();
     gen.writeln('Map<String, Function> _typeFactories = {');
-    types.forEach((Type type) {
-      gen.writeln("'${type.rawName}': ${type.name}.parse,");
+    types.forEach((Type? type) {
+      gen.writeln("'${type!.rawName}': ${type.name}.parse,");
     });
     gen.writeln('};');
     gen.writeln();
@@ -615,7 +617,7 @@
   Stream<Event> onEvent(String streamId);
 
   /// Handler for calling extra service extensions.
-  Future<Response> callServiceExtension(String method, {String isolateId, Map args});
+  Future<Response> callServiceExtension(String method, {String? isolateId, Map<String, dynamic>? args});
 ''');
     methods.forEach((m) {
       m.generateDefinition(gen);
@@ -628,14 +630,14 @@
     // automatically.
     gen.write('''
   class _PendingServiceRequest {
-    Future<Map<String, Object>> get future => _completer.future;
-    final _completer = Completer<Map<String, Object>>();
+    Future<Map<String, Object?>> get future => _completer.future;
+    final _completer = Completer<Map<String, Object?>>();
 
     final dynamic originalId;
 
     _PendingServiceRequest(this.originalId);
 
-    void complete(Map<String, Object> response) {
+    void complete(Map<String, Object?> response) {
       response['id'] = originalId;
       _completer.complete(response);
     }
@@ -649,7 +651,7 @@
   /// instances.
   class VmServerConnection {
     final Stream<Map<String, Object>> _requestStream;
-    final StreamSink<Map<String, Object>> _responseSink;
+    final StreamSink<Map<String, Object?>> _responseSink;
     final ServiceExtensionRegistry _serviceExtensionRegistry;
     final VmServiceInterface _serviceImplementation;
     /// Used to create unique ids when acting as a proxy between clients.
@@ -659,8 +661,8 @@
     final _streamSubscriptions = <String, StreamSubscription>{};
 
     /// Completes when [_requestStream] is done.
-    Future get done => _doneCompleter.future;
-    final _doneCompleter = Completer<Null>();
+    Future<void> get done => _doneCompleter.future;
+    final _doneCompleter = Completer<void>();
 
     /// Pending service extension requests to this client by id.
     final _pendingServiceExtensionRequests = <dynamic, _PendingServiceRequest>{};
@@ -678,13 +680,13 @@
     ///
     /// We don't attempt to do any serialization or deserialization of the
     /// request or response in this case
-    Future<Map<String, Object>> _forwardServiceExtensionRequest(
-        Map<String, Object> request) {
-      var originalId = request['id'];
-      request = Map.of(request);
+    Future<Map<String, Object?>> _forwardServiceExtensionRequest(
+        Map<String, Object?> request) {
+      final originalId = request['id'];
+      request = Map<String, Object?>.of(request);
       // Modify the request ID to ensure we don't have conflicts between
       // multiple clients ids.
-      var newId = '\${_nextServiceRequestId++}:\$originalId';
+      final newId = '\${_nextServiceRequestId++}:\$originalId';
       request['id'] = newId;
       var pendingRequest = _PendingServiceRequest(originalId);
       _pendingServiceExtensionRequests[newId] = pendingRequest;
@@ -692,22 +694,22 @@
       return pendingRequest.future;
     }
 
-    void _delegateRequest(Map<String, Object> request) async {
+    void _delegateRequest(Map<String, Object?> request) async {
       try {
         var id = request['id'];
         // Check if this is actually a response to a pending request.
         if (_pendingServiceExtensionRequests.containsKey(id)) {
-          final pending = _pendingServiceExtensionRequests[id];
-          pending.complete(Map.of(request));
+          final pending = _pendingServiceExtensionRequests[id]!;
+          pending.complete(Map<String, Object?>.of(request));
           return;
         }
-        var method = request['method'] as String;
+        final method = request['method'] as String?;
         if (method == null) {
           throw RPCError(
             null, RPCError.kInvalidRequest, 'Invalid Request', request);
         }
-        var params = request['params'] as Map;
-        Response response;
+        final params = request['params'] as Map<String, dynamic>?;
+        late Response response;
 
         switch(method) {
           case 'registerService':
@@ -722,14 +724,22 @@
         } else if (m.name == 'streamCancel') {
           gen.writeln(_streamCancelCaseImpl);
         } else {
+          bool firstParam = true;
+          final nullCheck = () {
+            final result = firstParam ? '!' : '';
+            if (firstParam) {
+              firstParam = false;
+            }
+            return result;
+          };
           gen.write("response = await _serviceImplementation.${m.name}(");
           // Positional args
           m.args.where((arg) => !arg.optional).forEach((MethodArg arg) {
             if (arg.type.isArray) {
               gen.write(
-                  "${arg.type.listCreationRef}.from(params['${arg.name}'] ?? []), ");
+                  "${arg.type.listCreationRef}.from(params${nullCheck()}['${arg.name}'] ?? []), ");
             } else {
-              gen.write("params['${arg.name}'], ");
+              gen.write("params${nullCheck()}['${arg.name}'], ");
             }
           });
           // Optional named args
@@ -738,9 +748,10 @@
             namedArgs.forEach((arg) {
               if (arg.name == 'scope') {
                 gen.writeln(
-                    "${arg.name}: params['${arg.name}']?.cast<String, String>(), ");
+                    "${arg.name}: params${nullCheck()}['${arg.name}']?.cast<String, String>(), ");
               } else {
-                gen.writeln("${arg.name}: params['${arg.name}'], ");
+                gen.writeln(
+                    "${arg.name}: params${nullCheck()}['${arg.name}'], ");
               }
             });
           }
@@ -752,7 +763,7 @@
     // Handle service extensions
     gen.writeln('default:');
     gen.writeln('''
-        var registeredClient = _serviceExtensionRegistry.clientFor(method);
+        final registeredClient = _serviceExtensionRegistry.clientFor(method);
         if (registeredClient != null) {
           // Check for any client which has registered this extension, if we
           // have one then delegate the request to that client.
@@ -764,8 +775,8 @@
         } else if (method.startsWith('ext.')) {
           // Remaining methods with `ext.` are assumed to be registered via
           // dart:developer, which the service implementation handles.
-          var args = params == null ? null : Map.of(params);
-          var isolateId = args?.remove('isolateId');
+          final args = params == null ? null : Map<String, dynamic>.of(params);
+          final isolateId = args?.remove('isolateId');
           response = await _serviceImplementation.callServiceExtension(method,
               isolateId: isolateId, args: args);
         } else {
@@ -775,13 +786,6 @@
     // Terminate the switch
     gen.writeln('}');
 
-    // Handle null responses
-    gen.write('''
-      if (response == null) {
-        throw StateError('Invalid null response from service');
-      }
-    ''');
-
     // Generate the json success response
     gen.write("""_responseSink.add({
   'jsonrpc': '2.0',
@@ -793,7 +797,7 @@
     // Close the try block, handle errors
     gen.write(r'''
       } catch (e, st) {
-        var error = e is RPCError
+        final error = e is RPCError
             ? e.toMap()
             : {
                 'code': RPCError.kInternalError,
@@ -817,13 +821,13 @@
 
     // The client side service implementation.
     gen.writeStatement('class VmService implements VmServiceInterface {');
-    gen.writeStatement('StreamSubscription _streamSub;');
-    gen.writeStatement('Function _writeMessage;');
+    gen.writeStatement('late final StreamSubscription _streamSub;');
+    gen.writeStatement('late final Function _writeMessage;');
     gen.writeStatement('int _id = 0;');
     gen.writeStatement('Map<String, Completer> _completers = {};');
     gen.writeStatement('Map<String, String> _methodCalls = {};');
     gen.writeStatement('Map<String, ServiceCallback> _services = {};');
-    gen.writeStatement('Log _log;');
+    gen.writeStatement('late final Log _log;');
     gen.write('''
 
 StreamController<String> _onSend = StreamController.broadcast(sync: true);
@@ -834,7 +838,7 @@
 Map<String, StreamController<Event>> _eventControllers = {};
 
 StreamController<Event> _getEventController(String eventName) {
-  StreamController<Event> controller = _eventControllers[eventName];
+  StreamController<Event>? controller = _eventControllers[eventName];
   if (controller == null) {
     controller = StreamController.broadcast();
     _eventControllers[eventName] = controller;
@@ -842,12 +846,12 @@
   return controller;
 }
 
-DisposeHandler _disposeHandler;
+late final DisposeHandler? _disposeHandler;
 
 VmService(Stream<dynamic> /*String|List<int>*/ inStream, void writeMessage(String message), {
-  Log log,
-  DisposeHandler disposeHandler,
-  Future streamClosed,
+  Log? log,
+  DisposeHandler? disposeHandler,
+  Future? streamClosed,
 }) {
   _streamSub = inStream.listen(_processMessage, onDone: ()=> _onDoneCompleter.complete());
   _writeMessage = writeMessage;
@@ -882,7 +886,7 @@
     });
     gen.writeln();
     gen.writeln('// types');
-    types.where((t) => !t.skip).forEach((t) => t.generate(gen));
+    types.where((t) => !t!.skip).forEach((t) => t!.generate(gen));
   }
 
   void generateAsserts(DartGenerator gen) {
@@ -903,17 +907,14 @@
 }
 
 bool assertBool(bool obj) {
-  assertNotNull(obj);
   return obj;
 }
 
 int assertInt(int obj) {
-  assertNotNull(obj);
   return obj;
 }
 
 double assertDouble(double obj) {
-  assertNotNull(obj);
   return obj;
 }
 
@@ -944,13 +945,11 @@
 }
 
 String assertString(String obj) {
-  assertNotNull(obj);
   if (obj.isEmpty) throw 'expected non-zero length string';
   return obj;
 }
 
 vms.Success assertSuccess(vms.Success obj) {
-  assertNotNull(obj);
   if (obj.type != 'Success') throw 'expected Success';
   return obj;
 }
@@ -964,10 +963,10 @@
       event.kind == vms.EventKind.kBreakpointAdded ||
       event.kind == vms.EventKind.kBreakpointRemoved ||
       event.kind == vms.EventKind.kBreakpointResolved) {
-    assertBreakpoint(event.breakpoint);
+    assertBreakpoint(event.breakpoint!);
   }
   if (event.kind == vms.EventKind.kPauseBreakpoint) {
-    for (vms.Breakpoint elem in event.pauseBreakpoints) {
+    for (vms.Breakpoint elem in event.pauseBreakpoints!) {
       assertBreakpoint(elem);
     }
   }
@@ -983,18 +982,18 @@
     if (event.topFrame != null ||
         (event.kind != vms.EventKind.kPauseInterrupted &&
             event.kind != vms.EventKind.kResume)) {
-      assertFrame(event.topFrame);
+      assertFrame(event.topFrame!);
     }
   }
   if (event.kind == vms.EventKind.kPauseException) {
-    assertInstanceRef(event.exception);
+    assertInstanceRef(event.exception!);
   }
   if (event.kind == vms.EventKind.kPauseBreakpoint ||
       event.kind == vms.EventKind.kPauseInterrupted) {
-    assertBool(event.atAsyncSuspension);
+    assertBool(event.atAsyncSuspension!);
   }
   if (event.kind == vms.EventKind.kInspect) {
-    assertInstanceRef(event.inspectee);
+    assertInstanceRef(event.inspectee!);
   }
   return event;
 }
@@ -1004,7 +1003,7 @@
 vms.Event assertIsolateEvent(vms.Event event) {
   assertEvent(event);
   if (event.kind == vms.EventKind.kServiceExtensionAdded) {
-    assertString(event.extensionRPC);
+    assertString(event.extensionRPC!);
   }
   return event;
 }
@@ -1013,10 +1012,10 @@
     for (Enum e in enums) {
       e.generateAssert(gen);
     }
-    for (Type type in types) {
-      if (type.name == 'Success') continue;
+    for (Type? type in types) {
+      if (type!.name == 'Success') continue;
       type.generateAssert(gen);
-      if (type.name.endsWith('Ref') ||
+      if (type.name!.endsWith('Ref') ||
           [
             'BoundVariable',
             'Breakpoint',
@@ -1029,6 +1028,7 @@
             'InboundReference',
             'LibraryDependency',
             'Message',
+            'ProcessMemoryItem',
             'ProfileFunction',
             'ProcessMemoryItem',
             'Protocol',
@@ -1043,16 +1043,17 @@
 
   void setDefaultValue(String typeName, String fieldName, String defaultValue) {
     types
-        .firstWhere((t) => t.name == typeName)
+        .firstWhere((t) => t!.name == typeName)!
         .fields
         .firstWhere((f) => f.name == fieldName)
         .defaultValue = defaultValue;
   }
 
-  bool isEnumName(String typeName) => enums.any((Enum e) => e.name == typeName);
+  bool isEnumName(String? typeName) =>
+      enums.any((Enum e) => e.name == typeName);
 
-  Type getType(String name) =>
-      types.firstWhere((t) => t.name == name, orElse: () => null);
+  Type? getType(String? name) =>
+      types.firstWhere((t) => t!.name == name, orElse: () => null);
 
   void _parseStreamListenDocs(String docs) {
     Iterator<String> lines = docs.split('\n').map((l) => l.trim()).iterator;
@@ -1090,8 +1091,8 @@
 }
 
 class StreamCategory {
-  String _name;
-  List<String> _events;
+  String? _name;
+  List<String>? _events;
 
   StreamCategory(String line) {
     // Debug | PauseStart, PauseExit, ...
@@ -1101,13 +1102,13 @@
     _events = line.split(',').map((w) => w.trim()).toList();
   }
 
-  String get name => _name;
+  String? get name => _name;
 
-  List<String> get events => _events;
+  List<String>? get events => _events;
 
   void generate(DartGenerator gen) {
     gen.writeln();
-    gen.writeln('// ${events.join(', ')}');
+    gen.writeln('// ${events!.join(', ')}');
     gen.writeln(
         "Stream<Event> get on${name}Event => _getEventController('$name').stream;");
   }
@@ -1117,7 +1118,7 @@
 
 class Method extends Member {
   final String name;
-  final String docs;
+  final String? docs;
 
   MemberType returnType = MemberType();
   List<MethodArg> args = [];
@@ -1142,7 +1143,7 @@
           .join());
 
       args.where((MethodArg a) => a.optional).forEach((MethodArg arg) {
-        String valueRef = arg.name;
+        String? valueRef = arg.name;
         // Special case for `getAllocationProfile`. We do not want to add these
         // params if they are false.
         if (name == 'getAllocationProfile') {
@@ -1173,7 +1174,7 @@
       {bool withDocs = true, bool withOverrides = false}) {
     gen.writeln();
     if (withDocs && docs != null) {
-      String _docs = docs == null ? '' : docs;
+      String _docs = docs == null ? '' : docs!;
       if (returnType.isMultipleReturns) {
         _docs += '\n\nThe return value can be one of '
             '${joinLast(returnType.types.map((t) => '[${t}]'), ', ', ' or ')}.';
@@ -1190,7 +1191,7 @@
     gen.write('Future<${returnType.name}> ${name}(');
     bool startedOptional = false;
     gen.write(args.map((MethodArg arg) {
-      String typeName;
+      String? typeName;
       if (api.isEnumName(arg.type.name)) {
         if (arg.type.isArray) {
           typeName = typeName = '/*${arg.type}*/ List<String>';
@@ -1200,12 +1201,12 @@
       } else {
         typeName = arg.type.ref;
       }
-
+      final nullable = arg.optional ? '?' : '';
       if (arg.optional && !startedOptional) {
         startedOptional = true;
-        return '{${typeName} ${arg.name}';
+        return '{${typeName}$nullable ${arg.name}';
       } else {
-        return '${typeName} ${arg.name}';
+        return '${typeName}$nullable ${arg.name}';
       }
     }).join(', '));
     if (args.length >= 4) gen.write(',');
@@ -1213,7 +1214,7 @@
     gen.write(') ');
   }
 
-  void _parse(Token token) => MethodParser(token).parseInto(this);
+  void _parse(Token? token) => MethodParser(token).parseInto(this);
 }
 
 class MemberType extends Member {
@@ -1229,7 +1230,7 @@
 
     while (loop) {
       if (parser.consume('(')) {
-        while (parser.peek().text != ')') {
+        while (parser.peek()!.text != ')') {
           // @Instance | Sentinel
           parser.advance();
         }
@@ -1258,7 +1259,7 @@
     }
   }
 
-  String get name {
+  String? get name {
     if (types.isEmpty) return '';
     if (types.length == 1) return types.first.ref;
     if (isReturnType) return 'Response';
@@ -1276,25 +1277,25 @@
 
   bool get isArray => types.length == 1 && types.first.isArray;
 
-  void generate(DartGenerator gen) => gen.write(name);
+  void generate(DartGenerator gen) => gen.write(name!);
 }
 
 class TypeRef {
-  String name;
+  String? name;
   int arrayDepth = 0;
-  List<TypeRef> genericTypes;
+  List<TypeRef>? genericTypes;
 
   TypeRef(this.name);
 
-  String get ref {
+  String? get ref {
     if (arrayDepth == 2) {
       return 'List<List<${name}>>';
     } else if (arrayDepth == 1) {
       return 'List<${name}>';
     } else if (genericTypes != null) {
-      return '$name<${genericTypes.join(', ')}>';
+      return '$name<${genericTypes!.join(', ')}>';
     } else {
-      return name.startsWith('_') ? name.substring(1) : name;
+      return name!.startsWith('_') ? name!.substring(1) : name;
     }
   }
 
@@ -1308,7 +1309,7 @@
     }
   }
 
-  String get listTypeArg => arrayDepth == 2 ? 'List<$name>' : name;
+  String? get listTypeArg => arrayDepth == 2 ? 'List<$name>' : name;
 
   bool get isArray => arrayDepth > 0;
 
@@ -1330,13 +1331,13 @@
           name == 'double' ||
           name == 'ByteData');
 
-  String toString() => ref;
+  String toString() => ref!;
 }
 
 class MethodArg extends Member {
   final Method parent;
   TypeRef type;
-  String name;
+  String? name;
   bool optional = false;
 
   MethodArg(this.parent, this.type, this.name);
@@ -1350,10 +1351,10 @@
 
 class Type extends Member {
   final Api parent;
-  String rawName;
-  String name;
-  String superName;
-  final String docs;
+  String? rawName;
+  String? name;
+  String? superName;
+  final String? docs;
   List<TypeField> fields = [];
 
   Type(this.parent, String categoryName, String definition, [this.docs]) {
@@ -1364,11 +1365,11 @@
 
   factory Type.merge(Type t1, Type t2) {
     final Api parent = t1.parent;
-    final String rawName = t1.rawName;
-    final String name = t1.name;
-    final String superName = t1.superName;
+    final String? rawName = t1.rawName;
+    final String? name = t1.name;
+    final String? superName = t1.superName;
     final String docs = [t1.docs, t2.docs].where((e) => e != null).join('\n');
-    final Map<String, TypeField> map = <String, TypeField>{};
+    final Map<String?, TypeField> map = <String?, TypeField>{};
     for (TypeField f in t2.fields.reversed) {
       map[f.name] = f;
     }
@@ -1385,17 +1386,17 @@
   bool get isResponse {
     if (superName == null) return false;
     if (name == 'Response' || superName == 'Response') return true;
-    return parent.getType(superName).isResponse;
+    return parent.getType(superName)!.isResponse;
   }
 
-  bool get isRef => name.endsWith('Ref');
+  bool get isRef => name!.endsWith('Ref');
 
   bool get supportsIdentity {
     if (fields.any((f) => f.name == 'id')) return true;
-    return superName == null ? false : getSuper().supportsIdentity;
+    return superName == null ? false : getSuper()!.supportsIdentity;
   }
 
-  Type getSuper() => superName == null ? null : api.getType(superName);
+  Type? getSuper() => superName == null ? null : api.getType(superName);
 
   List<TypeField> getAllFields() {
     if (superName == null) return fields;
@@ -1403,7 +1404,7 @@
     List<TypeField> all = [];
     all.insertAll(0, fields);
 
-    Type s = getSuper();
+    Type? s = getSuper();
     while (s != null) {
       all.insertAll(0, s.fields);
       s = s.getSuper();
@@ -1418,7 +1419,7 @@
     gen.writeln();
     if (docs != null) gen.writeDocs(docs);
     gen.write('class ${name} ');
-    Type superType;
+    Type? superType;
     if (superName != null) {
       superType = parent.getType(superName);
       gen.write('extends ${superName} ');
@@ -1427,12 +1428,12 @@
       gen.write('implements ${name}Ref ');
     }
     gen.writeln('{');
-    gen.writeln('static ${name} parse(Map<String, dynamic> json) => '
+    gen.writeln('static ${name}? parse(Map<String, dynamic>? json) => '
         'json == null ? null : ${name}._fromJson(json);');
     gen.writeln();
 
     if (name == 'Response' || name == 'TimelineEvent') {
-      gen.writeln('Map<String, dynamic> json;');
+      gen.writeln('Map<String, dynamic>? json;');
     }
     if (name == 'Script') {
       gen.writeln('final _tokenToLine = <int, int>{};');
@@ -1451,11 +1452,12 @@
     gen.write('${name}(');
     if (fields.isNotEmpty) {
       gen.write('{');
-      fields
-          .where((field) => !field.optional)
-          .forEach((field) => field.generateNamedParameter(gen));
+      fields.where((field) => !field.optional).forEach((field) {
+        final fromParent = (name == 'Instance' && field.name == 'classRef');
+        field.generateNamedParameter(gen, fromParent: fromParent);
+      });
       if (hasRequiredParentFields) {
-        superType.fields.where((field) => !field.optional).forEach(
+        superType!.fields.where((field) => !field.optional).forEach(
             (field) => field.generateNamedParameter(gen, fromParent: true));
       }
       fields
@@ -1466,12 +1468,23 @@
     gen.write(')');
     if (hasRequiredParentFields) {
       gen.write(' : super(');
-      superType.fields.where((field) => !field.optional).forEach((field) {
-        String name = field.generatableName;
-        gen.write('$name: $name');
+      superType!.fields.where((field) => !field.optional).forEach((field) {
+        String? name = field.generatableName;
+        gen.writeln('$name: $name,');
       });
+      if (name == 'Instance') {
+        gen.writeln('classRef: classRef,');
+      }
       gen.write(')');
+    } else if (name!.contains('NullVal')) {
+      gen.writeln(' : super(');
+      gen.writeln("id: 'instance/null',");
+      gen.writeln('kind: InstanceKind.kNull,');
+      gen.writeln("classRef: ClassRef(id: 'class/null',");
+      gen.writeln("name: 'Null',),");
+      gen.writeln(')');
     }
+
     gen.writeln(';');
 
     // Build from JSON.
@@ -1501,6 +1514,37 @@
         }
         if (field.defaultValue != null) {
           gen.write(' ?? ${field.defaultValue}');
+        } else if (!field.optional) {
+          // If a default isn't provided and the field is required, generate a
+          // sane default initializer to avoid TypeErrors at runtime when
+          // running in a null-safe context.
+          dynamic defaultValue;
+          switch (field.type.name) {
+            case 'int':
+            case 'num':
+            case 'double':
+              defaultValue = -1;
+              break;
+            case 'bool':
+              defaultValue = false;
+              break;
+            case 'String':
+              defaultValue = "''";
+              break;
+            case 'ByteData':
+              defaultValue = "ByteData(0)";
+              break;
+            default:
+              {
+                if (field.type.isEnum) {
+                  // TODO(bkonyi): Figure out if there's a more correct way to
+                  // determine a default value for enums.
+                  defaultValue = "''";
+                }
+                break;
+              }
+          }
+          gen.write(' ?? $defaultValue');
         }
         gen.writeln(';');
         // } else if (field.type.isEnum) {
@@ -1512,31 +1556,35 @@
         // Special case `Event.extensionData`.
         gen.writeln(
             "extensionData = ExtensionData.parse(json['extensionData']);");
-      } else if (name == 'Instance' && field.name == 'associations') {
-        // Special case `Instance.associations`.
-        gen.writeln("associations = json['associations'] == null "
-            "? null : List<MapAssociation>.from("
-            "_createSpecificObject(json['associations'], MapAssociation.parse));");
+      } else if (name == 'Instance') {
+        if (field.name == 'associations') {
+          // Special case `Instance.associations`.
+          gen.writeln("associations = json['associations'] == null "
+              "? null : List<MapAssociation>.from("
+              "_createSpecificObject(json['associations'], MapAssociation.parse));");
+        } else if (field.name == 'classRef') {
+          // This is populated by `Obj`
+        }
       } else if (name == '_CpuProfile' && field.name == 'codes') {
         // Special case `_CpuProfile.codes`.
         gen.writeln("codes = List<CodeRegion>.from("
-            "_createSpecificObject(json['codes'], CodeRegion.parse));");
+            "_createSpecificObject(json['codes']!, CodeRegion.parse));");
       } else if (name == '_CpuProfile' && field.name == 'functions') {
         // Special case `_CpuProfile.functions`.
         gen.writeln("functions = List<ProfileFunction>.from("
-            "_createSpecificObject(json['functions'], ProfileFunction.parse));");
+            "_createSpecificObject(json['functions']!, ProfileFunction.parse));");
       } else if (name == 'SourceReport' && field.name == 'ranges') {
         // Special case `SourceReport.ranges`.
         gen.writeln("ranges = List<SourceReportRange>.from("
-            "_createSpecificObject(json['ranges'], SourceReportRange.parse));");
+            "_createSpecificObject(json['ranges']!, SourceReportRange.parse));");
       } else if (name == 'SourceReportRange' && field.name == 'coverage') {
         // Special case `SourceReportRange.coverage`.
         gen.writeln("coverage = _createSpecificObject("
-            "json['coverage'], SourceReportCoverage.parse);");
+            "json['coverage']!, SourceReportCoverage.parse);");
       } else if (name == 'Library' && field.name == 'dependencies') {
         // Special case `Library.dependencies`.
         gen.writeln("dependencies = List<LibraryDependency>.from("
-            "_createSpecificObject(json['dependencies'], "
+            "_createSpecificObject(json['dependencies']!, "
             "LibraryDependency.parse));");
       } else if (name == 'Script' && field.name == 'tokenPosTable') {
         // Special case `Script.tokenPosTable`.
@@ -1544,7 +1592,7 @@
         if (field.optional) {
           gen.write("json['tokenPosTable'] == null ? null : ");
         }
-        gen.writeln("List<List<int>>.from(json['tokenPosTable'].map"
+        gen.writeln("List<List<int>>.from(json['tokenPosTable']!.map"
             "((dynamic list) => List<int>.from(list)));");
         gen.writeln('_parseTokenPosTable();');
       } else if (field.type.isArray) {
@@ -1557,7 +1605,7 @@
                 "List<${fieldType.listTypeArg}>.from($ref);");
           } else {
             gen.writeln("${field.generatableName} = $ref == null ? null : "
-                "List<${fieldType.listTypeArg}>.from(createServiceObject($ref, $typesList));");
+                "List<${fieldType.listTypeArg}>.from(createServiceObject($ref, $typesList)! as List);");
           }
         } else {
           if (fieldType.isListTypeSimple) {
@@ -1575,17 +1623,18 @@
             // field named 'samples' instead of 'instances'.
             if (name == 'InstanceSet') {
               gen.writeln("${field.generatableName} = "
-                  "List<${fieldType.listTypeArg}>.from(createServiceObject($ref ?? json['samples'], $typesList));");
+                  "List<${fieldType.listTypeArg}>.from(createServiceObject(($ref ?? json['samples']!) as List, $typesList)! as List);");
             } else {
               gen.writeln("${field.generatableName} = "
-                  "List<${fieldType.listTypeArg}>.from(createServiceObject($ref, $typesList) ?? []);");
+                  "List<${fieldType.listTypeArg}>.from(createServiceObject($ref, $typesList) as List? ?? []);");
             }
           }
         }
       } else {
         String typesList = _typeRefListToString(field.type.types);
         gen.writeln("${field.generatableName} = "
-            "createServiceObject(json['${field.name}'], $typesList);");
+            "createServiceObject(json['${field.name}']${field.optional ? '' : '!'}, "
+            "$typesList) as ${field.type.name}${field.optional ? '?' : ''};");
       }
     });
     if (fields.isNotEmpty) {
@@ -1599,10 +1648,13 @@
 
     // toJson support, the base Response type is not supported
     if (name == 'Response') {
+      gen.writeln("String get type => 'Response';");
+      gen.writeln();
       gen.writeln('''
 Map<String, dynamic> toJson() {
-  var result = json == null ? <String, dynamic>{} : Map.of(json);
-  result['type'] = type ?? 'Response';
+  final localJson = json;
+  final result = localJson == null ? <String, dynamic>{} : Map<String, dynamic>.of(localJson);
+  result['type'] = type;
   return result;
 }''');
     } else if (name == 'TimelineEvent') {
@@ -1610,7 +1662,8 @@
       // fairly dynamic. Return the json directly.
       gen.writeln('''
           Map<String, dynamic> toJson() {
-            var result = json == null ? <String, dynamic>{} : Map.of(json);
+            final localJson = json;
+            final result = localJson == null ? <String, dynamic>{} : Map<String, dynamic>.of(localJson);
             result['type'] = 'TimelineEvent';
             return result;
           }
@@ -1618,19 +1671,25 @@
     } else {
       if (isResponse) {
         gen.writeln('@override');
+        gen.writeln("String get type => '$name';");
+        gen.writeln();
+      }
+
+      if (isResponse) {
+        gen.writeln('@override');
       }
       gen.writeln('Map<String, dynamic> toJson() {');
       if (superName == null || superName == 'Response') {
         // The base Response type doesn't have a toJson
-        gen.writeln('var json = <String, dynamic>{};');
+        gen.writeln('final json = <String, dynamic>{};');
       } else {
-        gen.writeln('var json = super.toJson();');
+        gen.writeln('final json = super.toJson();');
       }
 
       // Only Response objects have a `type` field, as defined by protocol.
       if (isResponse) {
         // Overwrites "type" from the super class if we had one.
-        gen.writeln("json['type'] = '$rawName';");
+        gen.writeln("json['type'] = type;");
       }
 
       var requiredFields = fields.where((f) => !f.optional);
@@ -1682,7 +1741,8 @@
         }
         gen.writeln("String toString() => '[${name} ' //\n'${properties}]';");
       } else {
-        gen.writeln("String toString() => '[${name} ${properties}]';");
+        final formattedProperties = (properties.isEmpty) ? '' : ' $properties';
+        gen.writeln("String toString() => '[$name$formattedProperties]';");
       }
     } else {
       gen.writeln("String toString() => '[${name}]';");
@@ -1696,20 +1756,21 @@
     gen.writeDocs('''This function maps a token position to a line number.
 The VM considers the first line to be line 1.''');
     gen.writeln(
-        'int getLineNumberFromTokenPos(int tokenPos) => _tokenToLine[tokenPos];');
+        'int? getLineNumberFromTokenPos(int tokenPos) => _tokenToLine[tokenPos];');
     gen.writeln();
     gen.writeDocs('''This function maps a token position to a column number.
 The VM considers the first column to be column 1.''');
     gen.writeln(
-        'int getColumnNumberFromTokenPos(int tokenPos) => _tokenToColumn[tokenPos];');
+        'int? getColumnNumberFromTokenPos(int tokenPos) => _tokenToColumn[tokenPos];');
     gen.writeln();
     gen.writeln('''
 void _parseTokenPosTable() {
-  if (tokenPosTable == null) {
+  final tokenPositionTable = tokenPosTable;
+  if (tokenPositionTable == null) {
     return;
   }
-  final lineSet = Set<int>();
-  for (List line in tokenPosTable) {
+  final lineSet = <int>{};
+  for (List line in tokenPositionTable) {
     // Each entry begins with a line number...
     int lineNumber = line[0];
     lineSet.add(lineNumber);
@@ -1739,11 +1800,11 @@
       gen.write('${field.generatableName}$nullAware.map((f) => f');
       // Special case `tokenPosTable` which is a List<List<int>>.
       if (field.name == 'tokenPosTable') {
-        gen.write('$nullAware.toList()');
+        gen.write('.toList()');
       } else if (!field.type.types.first.isListTypeSimple) {
-        gen.write('$nullAware.toJson()');
+        gen.write('.toJson()');
       }
-      gen.write(')$nullAware.toList()');
+      gen.write(').toList()');
     } else {
       gen.write('${field.generatableName}$nullAware.toJson()');
     }
@@ -1759,8 +1820,8 @@
           TypeRef arrayType = type.types.first;
           if (arrayType.arrayDepth == 1) {
             String assertMethodName = 'assertListOf' +
-                arrayType.name.substring(0, 1).toUpperCase() +
-                arrayType.name.substring(1);
+                arrayType.name!.substring(0, 1).toUpperCase() +
+                arrayType.name!.substring(1);
             gen.writeln('$assertMethodName(obj.${field.generatableName});');
           } else {
             gen.writeln(
@@ -1774,8 +1835,8 @@
             gen.writeln(
                 'if (obj.${field.generatableName} is vms.${typeRef.name}) {');
             String assertMethodName = 'assert' +
-                typeRef.name.substring(0, 1).toUpperCase() +
-                typeRef.name.substring(1);
+                typeRef.name!.substring(0, 1).toUpperCase() +
+                typeRef.name!.substring(1);
             gen.writeln('$assertMethodName(obj.${field.generatableName});');
           }
           gen.writeln('} else {');
@@ -1784,8 +1845,8 @@
           gen.writeln('}');
         } else {
           String assertMethodName = 'assert' +
-              type.name.substring(0, 1).toUpperCase() +
-              type.name.substring(1);
+              type.name!.substring(0, 1).toUpperCase() +
+              type.name!.substring(1);
           gen.writeln('$assertMethodName(obj.${field.generatableName});');
         }
       }
@@ -1806,19 +1867,19 @@
     gen.writeln('');
   }
 
-  void _parse(Token token) => TypeParser(token).parseInto(this);
+  void _parse(Token? token) => TypeParser(token).parseInto(this);
 
   void calculateFieldOverrides() {
     for (TypeField field in fields.toList()) {
       if (superName == null) continue;
 
-      if (getSuper().hasField(field.name)) {
+      if (getSuper()!.hasField(field.name)) {
         field.setOverrides();
       }
     }
   }
 
-  bool hasField(String name) {
+  bool hasField(String? name) {
     if (fields.any((field) => field.name == name)) return true;
     return getSuper()?.hasField(name) ?? false;
   }
@@ -1836,19 +1897,19 @@
   };
 
   final Type parent;
-  final String _docs;
+  final String? _docs;
   MemberType type = MemberType();
-  String name;
+  String? name;
   bool optional = false;
-  String defaultValue;
+  String? defaultValue;
   bool overrides = false;
 
   TypeField(this.parent, this._docs);
 
   void setOverrides() => overrides = true;
 
-  String get docs {
-    String str = _docs == null ? '' : _docs;
+  String? get docs {
+    String str = _docs == null ? '' : _docs!;
     if (type.isMultipleReturns) {
       str += '\n\n[${generatableName}] can be one of '
           '${joinLast(type.types.map((t) => '[${t}]'), ', ', ' or ')}.';
@@ -1857,26 +1918,39 @@
     return str;
   }
 
-  String get generatableName {
+  String? get generatableName {
     return _nameRemap[name] != null ? _nameRemap[name] : name;
   }
 
   void generate(DartGenerator gen) {
-    if (docs.isNotEmpty) gen.writeDocs(docs);
+    if (docs!.isNotEmpty) gen.writeDocs(docs);
     if (optional) gen.write('@optional ');
     if (overrides) gen.write('@override ');
-    String typeName =
-        api.isEnumName(type.name) ? '/*${type.name}*/ String' : type.name;
-    gen.writeStatement('${typeName} ${generatableName};');
-    if (parent.fields.any((field) => field.hasDocs)) gen.writeln();
+    // Special case where Instance extends Obj, but 'classRef' is not optional
+    // for Instance although it is for Obj.
+    if (parent.name == 'Instance' && generatableName == 'classRef') {
+      gen.writeStatement('covariant late final ClassRef classRef;');
+    } else if (parent.name!.contains('NullVal') &&
+        generatableName == 'valueAsString') {
+      gen.writeStatement('covariant late final String valueAsString;');
+    } else {
+      String? typeName =
+          api.isEnumName(type.name) ? '/*${type.name}*/ String' : type.name;
+      if (optional) {
+        typeName = '$typeName?';
+      }
+      typeName = 'late final $typeName';
+      gen.writeStatement('${typeName} ${generatableName};');
+      if (parent.fields.any((field) => field.hasDocs)) gen.writeln();
+    }
   }
 
   void generateNamedParameter(DartGenerator gen, {bool fromParent = false}) {
     if (!optional) {
-      gen.write('@required ');
+      gen.write('required ');
     }
     if (fromParent) {
-      String typeName =
+      String? typeName =
           api.isEnumName(type.name) ? '/*${type.name}*/ String' : type.name;
       gen.writeStatement('$typeName ${generatableName},');
     } else {
@@ -1887,7 +1961,7 @@
 
 class Enum extends Member {
   final String name;
-  final String docs;
+  final String? docs;
 
   List<EnumValue> enums = [];
 
@@ -1900,7 +1974,7 @@
   factory Enum.merge(Enum e1, Enum e2) {
     final String name = e1.name;
     final String docs = [e1.docs, e2.docs].where((e) => e != null).join('\n');
-    final Map<String, EnumValue> map = <String, EnumValue>{};
+    final Map<String?, EnumValue> map = <String?, EnumValue>{};
     for (EnumValue e in e2.enums.reversed) {
       map[e.name] = e;
     }
@@ -1930,7 +2004,7 @@
   void generateAssert(DartGenerator gen) {
     gen.writeln('String assert${name}(String obj) {');
     List<EnumValue> sorted = enums.toList()
-      ..sort((EnumValue e1, EnumValue e2) => e1.name.compareTo(e2.name));
+      ..sort((EnumValue e1, EnumValue e2) => e1.name!.compareTo(e2.name!));
     for (EnumValue value in sorted) {
       gen.writeln('  if (obj == "${value.name}") return obj;');
     }
@@ -1939,13 +2013,13 @@
     gen.writeln('');
   }
 
-  void _parse(Token token) => EnumParser(token).parseInto(this);
+  void _parse(Token? token) => EnumParser(token).parseInto(this);
 }
 
 class EnumValue extends Member {
   final Enum parent;
-  final String name;
-  final String docs;
+  final String? name;
+  final String? docs;
 
   EnumValue(this.parent, this.name, [this.docs]);
 
@@ -1996,7 +2070,7 @@
   }
 
   void visitText(Text text) {
-    String t = text.text;
+    String? t = text.text;
     if (_em) {
       t = _coerceRefType(t);
     } else if (_href) {
@@ -2039,7 +2113,7 @@
 //     string targetId [optional],
 //     string expression)
 class MethodParser extends Parser {
-  MethodParser(Token startToken) : super(startToken);
+  MethodParser(Token? startToken) : super(startToken);
 
   void parseInto(Method method) {
     // method is return type, name, (, args )
@@ -2053,21 +2127,21 @@
 
     expect('(');
 
-    while (peek().text != ')') {
+    while (peek()!.text != ')') {
       Token type = expectName();
       TypeRef ref = TypeRef(_coerceRefType(type.text));
-      if (peek().text == '[') {
+      if (peek()!.text == '[') {
         while (consume('[')) {
           expect(']');
           ref.arrayDepth++;
         }
-      } else if (peek().text == '<') {
+      } else if (peek()!.text == '<') {
         // handle generics
         expect('<');
         ref.genericTypes = [];
-        while (peek().text != '>') {
+        while (peek()!.text != '>') {
           Token genericTypeName = expectName();
-          ref.genericTypes.add(TypeRef(_coerceRefType(genericTypeName.text)));
+          ref.genericTypes!.add(TypeRef(_coerceRefType(genericTypeName.text)));
           consume(',');
         }
         expect('>');
@@ -2095,7 +2169,7 @@
 }
 
 class TypeParser extends Parser {
-  TypeParser(Token startToken) : super(startToken);
+  TypeParser(Token? startToken) : super(startToken);
 
   void parseInto(Type type) {
     // class ClassList extends Response {
@@ -2114,7 +2188,7 @@
 
     expect('{');
 
-    while (peek().text != '}') {
+    while (peek()!.text != '}') {
       TypeField field = TypeField(type, collectComments());
       field.type.parse(this);
       field.name = expectName().text;
@@ -2137,6 +2211,8 @@
       dataField.name = 'data';
       dataField.optional = true;
       type.fields.add(dataField);
+    } else if (type.rawName == 'Response') {
+      type.fields.removeWhere((field) => field.name == 'type');
     }
 
     expect('}');
@@ -2144,7 +2220,7 @@
 }
 
 class EnumParser extends Parser {
-  EnumParser(Token startToken) : super(startToken);
+  EnumParser(Token? startToken) : super(startToken);
 
   void parseInto(Enum e) {
     // enum ErrorKind { UnhandledException, Foo, Bar }
@@ -2157,7 +2233,7 @@
 
     while (!t.eof) {
       if (consume('}')) break;
-      String docs = collectComments();
+      String? docs = collectComments();
       t = expectName();
       consume(',');
 
diff --git a/pkg/vm_service/tool/dart/src_gen_dart.dart b/pkg/vm_service/tool/dart/src_gen_dart.dart
index 15cf723..e343e37 100644
--- a/pkg/vm_service/tool/dart/src_gen_dart.dart
+++ b/pkg/vm_service/tool/dart/src_gen_dart.dart
@@ -25,7 +25,7 @@
   /// Write out the given dartdoc text, wrapping lines as necessary to flow
   /// along the column boundary. If [preferSingle] is true, and the docs would
   /// fit on a single line, use `///` dartdoc style.
-  void writeDocs(String docs) {
+  void writeDocs(String? docs) {
     if (docs == null) return;
 
     docs = wrap(docs.trim(), colBoundary - _indent.length - 4);
diff --git a/pkg/vm_service/tool/generate.dart b/pkg/vm_service/tool/generate.dart
index 28dc548..bea71f8 100644
--- a/pkg/vm_service/tool/generate.dart
+++ b/pkg/vm_service/tool/generate.dart
@@ -4,6 +4,9 @@
 
 import 'dart:io';
 
+// TODO(bkonyi): remove once markdown and pub_semver deps are updated to null
+// safety for the SDK.
+// ignore_for_file: import_of_legacy_library_into_null_safe
 import 'package:markdown/markdown.dart';
 import 'package:path/path.dart';
 import 'package:pub_semver/pub_semver.dart';
@@ -132,8 +135,8 @@
     if (line.startsWith(pattern)) {
       found = true;
       Version v = Version.parse(line.substring(pattern.length));
-      String pre = v.preRelease.isEmpty ? null : v.preRelease.join('-');
-      String build = v.build.isEmpty ? null : v.build.join('+');
+      String? pre = v.preRelease.isEmpty ? null : v.preRelease.join('-');
+      String? build = v.build.isEmpty ? null : v.build.join('+');
       v = Version(version.major, version.minor, v.patch,
           pre: pre, build: build);
       return '${pattern}${v.toString()}';
diff --git a/pkg/vm_service/tool/java/generate_java.dart b/pkg/vm_service/tool/java/generate_java.dart
index 675ce5b..3a3567a 100644
--- a/pkg/vm_service/tool/java/generate_java.dart
+++ b/pkg/vm_service/tool/java/generate_java.dart
@@ -4,6 +4,9 @@
 
 library generate_vm_service_java;
 
+// TODO(bkonyi): remove once markdown and pub_semver deps are updated to null
+// safety for the SDK.
+// ignore_for_file: import_of_legacy_library_into_null_safe
 import 'package:markdown/markdown.dart';
 import 'package:pub_semver/pub_semver.dart';
 
@@ -50,11 +53,11 @@
 from within any {@link Consumer} method.
 ''';
 
-Api api;
+late Api api;
 
 /// Convert documentation references
 /// from spec style of [className] to javadoc style {@link className}
-String convertDocLinks(String doc) {
+String? convertDocLinks(String? doc) {
   if (doc == null) return null;
   var sb = StringBuffer();
   int start = 0;
@@ -78,14 +81,14 @@
   return sb.toString();
 }
 
-String _coerceRefType(String typeName) {
+String? _coerceRefType(String? typeName) {
   if (typeName == 'Class') typeName = 'ClassObj';
   if (typeName == 'Error') typeName = 'ErrorObj';
   if (typeName == 'Object') typeName = 'Obj';
   if (typeName == '@Object') typeName = 'ObjRef';
   if (typeName == 'Function') typeName = 'Func';
   if (typeName == '@Function') typeName = 'FuncRef';
-  if (typeName.startsWith('@')) typeName = typeName.substring(1) + 'Ref';
+  if (typeName!.startsWith('@')) typeName = typeName.substring(1) + 'Ref';
   if (typeName == 'string') typeName = 'String';
   if (typeName == 'bool') typeName = 'boolean';
   if (typeName == 'num') typeName = 'BigDecimal';
@@ -94,20 +97,20 @@
 }
 
 class Api extends Member with ApiParseUtil {
-  int serviceMajor;
-  int serviceMinor;
-  String serviceVersion;
+  int? serviceMajor;
+  int? serviceMinor;
+  String? serviceVersion;
   List<Method> methods = [];
-  List<Enum> enums = [];
-  List<Type> types = [];
+  List<Enum?> enums = [];
+  List<Type?> types = [];
   Map<String, List<String>> streamIdMap = {};
 
-  String get docs => null;
+  String? get docs => null;
 
   String get name => 'api';
 
-  void addProperty(String typeName, String propertyName, {String javadoc}) {
-    var t = types.firstWhere((t) => t.name == typeName);
+  void addProperty(String typeName, String propertyName, {String? javadoc}) {
+    var t = types.firstWhere((t) => t!.name == typeName)!;
     for (var f in t.fields) {
       if (f.name == propertyName) {
         print('$typeName already has $propertyName field');
@@ -133,13 +136,13 @@
     for (var m in methods) {
       for (var a in m.args) {
         if (a.hasDocs) continue;
-        var t = types.firstWhere((Type t) => t.name == a.type.name,
+        var t = types.firstWhere((Type? t) => t!.name == a.type.name,
             orElse: () => null);
         if (t != null) {
           a.docs = t.docs;
           continue;
         }
-        var e = enums.firstWhere((Enum e) => e.name == a.type.name,
+        var e = enums.firstWhere((Enum? e) => e!.name == a.type.name,
             orElse: () => null);
         if (e != null) {
           a.docs = e.docs;
@@ -234,17 +237,18 @@
       m.generateConsumerInterface(gen);
     }
     for (var t in types) {
-      t.generateElement(gen);
+      t!.generateElement(gen);
     }
     for (var e in enums) {
-      e.generateEnum(gen);
+      e!.generateEnum(gen);
     }
   }
 
-  Type getType(String name) =>
-      types.firstWhere((t) => t.name == name, orElse: () => null);
+  Type? getType(String? name) =>
+      types.firstWhere((t) => t!.name == name, orElse: () => null);
 
-  bool isEnumName(String typeName) => enums.any((Enum e) => e.name == typeName);
+  bool isEnumName(String? typeName) =>
+      enums.any((Enum? e) => e!.name == typeName);
 
   void parse(List<Node> nodes) {
     Version version = ApiParseUtil.parseVersionSemVer(nodes);
@@ -256,17 +260,17 @@
     // the pre following it is the definition
     // the optional p following that is the documentation
 
-    String h3Name;
+    String? h3Name;
 
     for (int i = 0; i < nodes.length; i++) {
       Node node = nodes[i];
 
       if (isPre(node) && h3Name != null) {
         String definition = textForCode(node);
-        String docs;
+        String? docs;
 
         if (i + 1 < nodes.length && isPara(nodes[i + 1])) {
-          Element p = nodes[++i];
+          Element p = nodes[++i] as Element;
           docs = collapseWhitespace(TextOutputVisitor.printText(p));
         }
 
@@ -288,18 +292,18 @@
         }
       }
     }
-    for (Type type in types) {
-      type.calculateFieldOverrides();
+    for (Type? type in types) {
+      type!.calculateFieldOverrides();
     }
   }
 
   void setDefaultValue(String typeName, String propertyName) {
-    var type = types.firstWhere((t) => t.name == typeName);
+    var type = types.firstWhere((t) => t!.name == typeName)!;
     var field = type.fields.firstWhere((f) => f.name == propertyName);
     field.defaultValue = 'false';
   }
 
-  void _parse(String name, String definition, [String docs]) {
+  void _parse(String name, String definition, [String? docs]) {
     name = name.trim();
     definition = definition.trim();
     // clean markdown introduced changes
@@ -361,7 +365,7 @@
 
 class Enum extends Member {
   final String name;
-  final String docs;
+  final String? docs;
 
   List<EnumValue> enums = [];
 
@@ -375,7 +379,7 @@
     gen.writeType(elementTypeName, (TypeWriter writer) {
       writer.javadoc = convertDocLinks(docs);
       writer.isEnum = true;
-      enums.sort((v1, v2) => v1.name.compareTo(v2.name));
+      enums.sort((v1, v2) => v1.name!.compareTo(v2.name!));
       for (var value in enums) {
         writer.addEnumValue(value.name, javadoc: value.docs);
       }
@@ -386,13 +390,13 @@
     });
   }
 
-  void _parse(Token token) {
+  void _parse(Token? token) {
     EnumParser(token).parseInto(this);
   }
 }
 
 class EnumParser extends Parser {
-  EnumParser(Token startToken) : super(startToken);
+  EnumParser(Token? startToken) : super(startToken);
 
   void parseInto(Enum e) {
     // enum ErrorKind { UnhandledException, Foo, Bar }
@@ -405,7 +409,7 @@
 
     while (!t.eof) {
       if (consume('}')) break;
-      String docs = collectComments();
+      String? docs = collectComments();
       t = expectName();
       consume(',');
 
@@ -416,8 +420,8 @@
 
 class EnumValue extends Member {
   final Enum parent;
-  final String name;
-  final String docs;
+  final String? name;
+  final String? docs;
 
   EnumValue(this.parent, this.name, [this.docs]);
 
@@ -425,13 +429,13 @@
 }
 
 abstract class Member {
-  String get docs => null;
+  String? get docs => null;
 
   bool get hasDocs => docs != null;
 
-  String get name;
+  String? get name;
 
-  String toString() => name;
+  String toString() => name!;
 }
 
 class MemberType extends Member {
@@ -449,13 +453,13 @@
 
   bool get isValueAndSentinel => types.length == 2 && hasSentinel;
 
-  String get name {
+  String? get name {
     if (types.isEmpty) return '';
     if (types.length == 1) return types.first.ref;
     return 'dynamic';
   }
 
-  TypeRef get valueType {
+  TypeRef? get valueType {
     if (types.length == 1) return types.first;
     if (isValueAndSentinel) {
       return types.firstWhere((t) => t.name != 'Sentinel');
@@ -492,7 +496,7 @@
 
 class Method extends Member {
   final String name;
-  final String docs;
+  final String? docs;
 
   MemberType returnType = MemberType();
   List<MethodArg> args = [];
@@ -502,7 +506,7 @@
   }
 
   String get consumerTypeName {
-    String prefix;
+    String? prefix;
     if (returnType.isMultipleReturns) {
       prefix = titleCase(name);
     } else {
@@ -531,13 +535,13 @@
   void generateVmServiceForward(StatementWriter writer) {
     var consumerName = classNameFor(consumerTypeName);
     writer.addLine('if (consumer instanceof $consumerName) {');
-    List<Type> types = List.from(returnType.types.map((ref) => ref.type));
+    List<Type?> types = List.from(returnType.types.map((ref) => ref.type));
     for (int index = 0; index < types.length; ++index) {
-      types.addAll(types[index].subtypes);
+      types.addAll(types[index]!.subtypes);
     }
-    types.sort((t1, t2) => t1.name.compareTo(t2.name));
+    types.sort((t1, t2) => t1!.name!.compareTo(t2!.name!));
     for (var t in types) {
-      var responseName = classNameFor(t.elementTypeName);
+      var responseName = classNameFor(t!.elementTypeName!);
       writer.addLine('  if (responseType.equals("${t.rawName}")) {');
       writer.addLine(
           '    (($consumerName) consumer).received(new $responseName(json));');
@@ -557,7 +561,7 @@
 //    }
 
     // Update method docs
-    var javadoc = StringBuffer(docs == null ? '' : docs);
+    var javadoc = StringBuffer(docs == null ? '' : docs!);
     bool firstParamDoc = true;
     for (var a in args) {
       if (!includeOptional && a.optional) continue;
@@ -611,7 +615,7 @@
     }, javadoc: javadoc.toString());
   }
 
-  void _parse(Token token) {
+  void _parse(Token? token) {
     MethodParser(token).parseInto(this);
   }
 }
@@ -619,8 +623,8 @@
 class MethodArg extends Member {
   final Method parent;
   final TypeRef type;
-  String name;
-  String docs;
+  String? name;
+  String? docs;
   bool optional = false;
 
   MethodArg(this.parent, this.type, this.name);
@@ -643,7 +647,7 @@
 }
 
 class MethodParser extends Parser {
-  MethodParser(Token startToken) : super(startToken);
+  MethodParser(Token? startToken) : super(startToken);
 
   void parseInto(Method method) {
     // method is return type, name, (, args )
@@ -657,21 +661,21 @@
 
     expect('(');
 
-    while (peek().text != ')') {
+    while (peek()!.text != ')') {
       Token type = expectName();
       TypeRef ref = TypeRef(_coerceRefType(type.text));
-      if (peek().text == '[') {
+      if (peek()!.text == '[') {
         while (consume('[')) {
           expect(']');
           ref.arrayDepth++;
         }
-      } else if (peek().text == '<') {
+      } else if (peek()!.text == '<') {
         // handle generics
         expect('<');
         ref.genericTypes = [];
-        while (peek().text != '>') {
+        while (peek()!.text != '>') {
           Token genericTypeName = expectName();
-          ref.genericTypes.add(TypeRef(_coerceRefType(genericTypeName.text)));
+          ref.genericTypes!.add(TypeRef(_coerceRefType(genericTypeName.text)));
           consume(',');
         }
         expect('>');
@@ -719,7 +723,7 @@
   }
 
   void visitText(Text text) {
-    String t = text.text;
+    String? t = text.text;
     if (_inRef) t = _coerceRefType(t);
     buf.write(t);
   }
@@ -742,27 +746,27 @@
 
 class Type extends Member {
   final Api parent;
-  String rawName;
-  String name;
-  String superName;
-  final String docs;
+  String? rawName;
+  String? name;
+  String? superName;
+  final String? docs;
   List<TypeField> fields = [];
 
   Type(this.parent, String categoryName, String definition, [this.docs]) {
     _parse(Tokenizer(definition).tokenize());
   }
 
-  String get elementTypeName {
+  String? get elementTypeName {
     if (isSimple) return null;
     return '$servicePackage.element.$name';
   }
 
-  bool get isRef => name.endsWith('Ref');
+  bool get isRef => name!.endsWith('Ref');
 
   bool get isResponse {
     if (superName == null) return false;
     if (name == 'Response' || superName == 'Response') return true;
-    return parent.getType(superName).isResponse;
+    return parent.getType(superName)!.isResponse;
   }
 
   bool get isSimple => simpleTypes.contains(name);
@@ -773,8 +777,8 @@
     return name;
   }
 
-  Iterable<Type> get subtypes =>
-      api.types.toList()..retainWhere((t) => t.superName == name);
+  Iterable<Type?> get subtypes =>
+      api.types.toList()..retainWhere((t) => t!.superName == name);
 
   void generateElement(JavaGenerator gen) {
     gen.writeType('$servicePackage.element.$name', (TypeWriter writer) {
@@ -814,7 +818,7 @@
     List<TypeField> all = [];
     all.insertAll(0, fields);
 
-    Type s = getSuper();
+    Type? s = getSuper();
     while (s != null) {
       all.insertAll(0, s.fields);
       s = s.getSuper();
@@ -823,14 +827,14 @@
     return all;
   }
 
-  Type getSuper() => superName == null ? null : api.getType(superName);
+  Type? getSuper() => superName == null ? null : api.getType(superName);
 
-  bool hasField(String name) {
+  bool hasField(String? name) {
     if (fields.any((field) => field.name == name)) return true;
     return getSuper()?.hasField(name) ?? false;
   }
 
-  void _parse(Token token) {
+  void _parse(Token? token) {
     TypeParser(token).parseInto(this);
   }
 
@@ -838,7 +842,7 @@
     for (TypeField field in fields.toList()) {
       if (superName == null) continue;
 
-      if (getSuper().hasField(field.name)) {
+      if (getSuper()!.hasField(field.name)) {
         field.setOverrides();
       }
     }
@@ -860,11 +864,11 @@
   };
 
   final Type parent;
-  final String _docs;
+  final String? _docs;
   MemberType type = MemberType();
-  String name;
+  String? name;
   bool optional = false;
-  String defaultValue;
+  String? defaultValue;
   bool overrides = false;
 
   TypeField(this.parent, this._docs);
@@ -880,11 +884,11 @@
     } else {
       remappedName = name;
     }
-    return 'get${titleCase(remappedName)}';
+    return 'get${titleCase(remappedName!)}';
   }
 
-  String get docs {
-    String str = _docs == null ? '' : _docs;
+  String? get docs {
+    String str = _docs == null ? '' : _docs!;
     if (type.isMultipleReturns) {
       str += '\n\n@return one of '
           '${joinLast(type.types.map((t) => '<code>${t}</code>'), ', ', ' or ')}';
@@ -904,7 +908,7 @@
         w.addLine('final JsonObject elem = (JsonObject)json.get("$name");');
         w.addLine('if (elem == null) return null;\n');
         for (TypeRef t in type.types) {
-          String refName = t.name;
+          String refName = t.name!;
           if (refName.endsWith('Ref')) {
             refName = "@" + refName.substring(0, refName.length - 3);
           }
@@ -914,7 +918,7 @@
         w.addLine('return null;');
       }, javadoc: docs, returnType: 'Object');
     } else {
-      String returnType = type.valueType.ref;
+      String? returnType = type.valueType!.ref;
       if (name == 'timestamp') {
         returnType = 'long';
       }
@@ -923,7 +927,7 @@
         accessorName,
         [],
         (StatementWriter writer) {
-          type.valueType.generateAccessStatements(
+          type.valueType!.generateAccessStatements(
             writer,
             name,
             canBeSentinel: type.isValueAndSentinel,
@@ -940,7 +944,7 @@
 }
 
 class TypeParser extends Parser {
-  TypeParser(Token startToken) : super(startToken);
+  TypeParser(Token? startToken) : super(startToken);
 
   void parseInto(Type type) {
     // class ClassList extends Response {
@@ -959,7 +963,7 @@
 
     expect('{');
 
-    while (peek().text != '}') {
+    while (peek()!.text != '}') {
       TypeField field = TypeField(type, collectComments());
       field.type.parse(this);
       field.name = expectName().text;
@@ -977,13 +981,13 @@
 }
 
 class TypeRef {
-  String name;
+  String? name;
   int arrayDepth = 0;
-  List<TypeRef> genericTypes;
+  List<TypeRef>? genericTypes;
 
   TypeRef(this.name);
 
-  String get elementTypeName {
+  String? get elementTypeName {
     if (isSimple) return null;
     return '$servicePackage.element.$name';
   }
@@ -991,20 +995,20 @@
   bool get isArray => arrayDepth > 0;
 
   /// Hacked enum determination
-  bool get isEnum => name.endsWith('Kind') || name.endsWith('Mode');
+  bool get isEnum => name!.endsWith('Kind') || name!.endsWith('Mode');
 
   bool get isSimple => simpleTypes.contains(name);
 
-  String get javaBoxedName {
+  String? get javaBoxedName {
     if (name == 'boolean') return 'Boolean';
     if (name == 'int') return 'Integer';
     if (name == 'double') return 'Double';
     return name;
   }
 
-  String get ref {
+  String? get ref {
     if (genericTypes != null) {
-      return '$name<${genericTypes.join(', ')}>';
+      return '$name<${genericTypes!.join(', ')}>';
     } else if (isSimple) {
       if (arrayDepth == 2) return 'List<List<${javaBoxedName}>>';
       if (arrayDepth == 1) return 'List<${javaBoxedName}>';
@@ -1015,13 +1019,13 @@
     return name;
   }
 
-  Type get type => api.types.firstWhere((t) => t.name == name);
+  Type? get type => api.types.firstWhere((t) => t!.name == name);
 
   void generateAccessStatements(
     StatementWriter writer,
-    String propertyName, {
+    String? propertyName, {
     bool canBeSentinel = false,
-    String defaultValue,
+    String? defaultValue,
     bool optional = false,
   }) {
     if (name == 'boolean') {
@@ -1144,5 +1148,5 @@
     }
   }
 
-  String toString() => ref;
+  String toString() => ref!;
 }
diff --git a/pkg/vm_service/tool/java/src_gen_java.dart b/pkg/vm_service/tool/java/src_gen_java.dart
index 91b71e2..b67c203 100644
--- a/pkg/vm_service/tool/java/src_gen_java.dart
+++ b/pkg/vm_service/tool/java/src_gen_java.dart
@@ -15,7 +15,7 @@
 int colBoundary = 100;
 
 /// The header for every generated file.
-String fileHeader;
+String? fileHeader;
 
 String classNameFor(String typeName) {
   // Convert ElementList<Foo> param declarations to List<Foo> declarations.
@@ -71,8 +71,8 @@
 }
 
 class JavaMethodArg {
-  final String name;
-  final String typeName;
+  final String? name;
+  final String? typeName;
 
   JavaMethodArg(this.name, this.typeName);
 }
@@ -115,10 +115,10 @@
   final String className;
   bool isInterface = false;
   bool isEnum = false;
-  String javadoc;
+  String? javadoc;
   String modifiers = 'public';
   final Set<String> _imports = Set<String>();
-  String superclassName;
+  String? superclassName;
   List<String> interfaceNames = <String>[];
   final StringBuffer _content = StringBuffer();
   final List<String> _fields = <String>[];
@@ -135,7 +135,7 @@
   }
 
   void addConstructor(Iterable<JavaMethodArg> args, WriteStatements write,
-      {String javadoc, String modifiers = 'public'}) {
+      {String? javadoc, String modifiers = 'public'}) {
     _content.writeln();
     if (javadoc != null && javadoc.isNotEmpty) {
       _content.writeln('  /**');
@@ -146,22 +146,18 @@
     }
     _content.write('  $modifiers $className(');
     _content.write(
-        args.map((a) => '${classNameFor(a.typeName)} ${a.name}').join(', '));
+        args.map((a) => '${classNameFor(a.typeName!)} ${a.name}').join(', '));
     _content.write(')');
-    if (write != null) {
-      _content.writeln(' {');
-      StatementWriter writer = StatementWriter(this);
-      write(writer);
-      _content.write(writer.toSource());
-      _content.writeln('  }');
-    } else {
-      _content.writeln(';');
-    }
+    _content.writeln(' {');
+    StatementWriter writer = StatementWriter(this);
+    write(writer);
+    _content.write(writer.toSource());
+    _content.writeln('  }');
   }
 
   void addEnumValue(
-    String name, {
-    String javadoc,
+    String? name, {
+    String? javadoc,
     bool isLast = false,
   }) {
     _content.writeln();
@@ -181,7 +177,7 @@
   }
 
   void addField(String name, String typeName,
-      {String modifiers = 'public', String value, String javadoc}) {
+      {String modifiers = 'public', String? value, String? javadoc}) {
     var fieldDecl = StringBuffer();
     if (javadoc != null && javadoc.isNotEmpty) {
       fieldDecl.writeln('  /**');
@@ -191,7 +187,7 @@
       fieldDecl.writeln('   */');
     }
     fieldDecl.write('  ');
-    if (modifiers != null && modifiers.isNotEmpty) {
+    if (modifiers.isNotEmpty) {
       fieldDecl.write('$modifiers ');
     }
     fieldDecl.write('$typeName $name');
@@ -202,7 +198,7 @@
     _fields.add(fieldDecl.toString());
   }
 
-  void addImport(String typeName) {
+  void addImport(String? typeName) {
     if (typeName == null || typeName.isEmpty) return;
     var pkgName = pkgNameFor(typeName);
     if (pkgName.isNotEmpty && pkgName != this.pkgName) {
@@ -213,10 +209,10 @@
   void addMethod(
     String name,
     Iterable<JavaMethodArg> args,
-    WriteStatements write, {
-    String javadoc,
-    String modifiers = 'public',
-    String returnType = 'void',
+    WriteStatements? write, {
+    String? javadoc,
+    String? modifiers = 'public',
+    String? returnType = 'void',
     bool isOverride = false,
   }) {
     var methodDecl = StringBuffer();
@@ -238,7 +234,8 @@
     }
     methodDecl.write('$returnType $name(');
     methodDecl.write(args
-        .map((JavaMethodArg arg) => '${classNameFor(arg.typeName)} ${arg.name}')
+        .map(
+            (JavaMethodArg arg) => '${classNameFor(arg.typeName!)} ${arg.name}')
         .join(', '));
     methodDecl.write(')');
     if (write != null) {
@@ -260,10 +257,8 @@
   String toSource() {
     var buffer = StringBuffer();
     if (fileHeader != null) buffer.write(fileHeader);
-    if (pkgName != null) {
-      buffer.writeln('package $pkgName;');
-      buffer.writeln();
-    }
+    buffer.writeln('package $pkgName;');
+    buffer.writeln();
     buffer.writeln('// This is a generated file.');
     buffer.writeln();
     addImport(superclassName);
@@ -275,9 +270,9 @@
       }
       buffer.writeln();
     }
-    if (javadoc != null && javadoc.isNotEmpty) {
+    if (javadoc != null && javadoc!.isNotEmpty) {
       buffer.writeln('/**');
-      wrap(javadoc.trim(), colBoundary - 4)
+      wrap(javadoc!.trim(), colBoundary - 4)
           .split('\n')
           .forEach((line) => buffer.writeln(' * $line'));
       buffer.writeln(' */');
@@ -287,7 +282,7 @@
 
     buffer.write('$modifiers $kind $className');
     if (superclassName != null) {
-      buffer.write(' extends ${classNameFor(superclassName)}');
+      buffer.write(' extends ${classNameFor(superclassName!)}');
     }
     if (interfaceNames.isNotEmpty) {
       var classNames = interfaceNames.map((t) => classNameFor(t));
diff --git a/runtime/tests/vm/dart/regress_42067_test.dart b/runtime/tests/vm/dart/regress_42067_test.dart
new file mode 100644
index 0000000..21f87c8
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_42067_test.dart
@@ -0,0 +1,47 @@
+// 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.
+
+// VMOptions=--deterministic --optimization_counter_threshold=100
+
+// Verifies correct code is generated for Float64x2.fromFloat32x4 in case of
+// high register pressure.
+// Regression test for https://github.com/dart-lang/sdk/issues/42067.
+
+import 'dart:typed_data';
+
+import 'package:expect/expect.dart';
+
+@pragma('vm:never-inline')
+doTest(double x) {
+  Float32x4 a0 = Float32x4.splat(x + 1);
+  Float32x4 a1 = Float32x4.splat(x + 2);
+  Float32x4 a2 = Float32x4.splat(x + 3);
+  Float32x4 a3 = Float32x4.splat(x + 4);
+  Float32x4 a4 = Float32x4.splat(x + 5);
+  Float32x4 a5 = Float32x4.splat(x + 6);
+  Float32x4 a6 = Float32x4.splat(x + 7);
+  Float32x4 a7 = Float32x4.splat(x + 8);
+  return Float64x2.fromFloat32x4(a0) +
+      Float64x2.fromFloat32x4(a1) +
+      Float64x2.fromFloat32x4(a2) +
+      Float64x2.fromFloat32x4(a3) +
+      Float64x2.fromFloat32x4(a4) +
+      Float64x2.fromFloat32x4(a5) +
+      Float64x2.fromFloat32x4(a6) +
+      Float64x2.fromFloat32x4(a7) +
+      Float64x2.fromFloat32x4(a0) +
+      Float64x2.fromFloat32x4(a1) +
+      Float64x2.fromFloat32x4(a2) +
+      Float64x2.fromFloat32x4(a3) +
+      Float64x2.fromFloat32x4(a4) +
+      Float64x2.fromFloat32x4(a5) +
+      Float64x2.fromFloat32x4(a6) +
+      Float64x2.fromFloat32x4(a7);
+}
+
+void main() {
+  for (int i = 0; i < 200; ++i) {
+    Expect.approxEquals(88.0, doTest(1.0).x);
+  }
+}
diff --git a/runtime/tests/vm/dart/split_literals.dart b/runtime/tests/vm/dart/split_literals.dart
new file mode 100644
index 0000000..b71e9bd
--- /dev/null
+++ b/runtime/tests/vm/dart/split_literals.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "split_literals_deferred.dart" deferred as lib;
+
+class Box {
+  final contents;
+  const Box(this.contents);
+  String toString() => "Box($contents)";
+}
+
+main() async {
+  print("Root literal!");
+  print(const <String>["Root literal in a list!"]);
+  print(const <String, String>{"key": "Root literal in a map!"});
+  print(const Box("Root literal in a box!"));
+
+  await lib.loadLibrary();
+  lib.foo();
+}
diff --git a/runtime/tests/vm/dart/split_literals_deferred.dart b/runtime/tests/vm/dart/split_literals_deferred.dart
new file mode 100644
index 0000000..015ae1d
--- /dev/null
+++ b/runtime/tests/vm/dart/split_literals_deferred.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "split_literals.dart";
+
+void foo() {
+  print("Deferred literal!");
+  print(const <String>["Deferred literal in a list!"]);
+  print(const <String, String>{"key": "Deferred literal in a map!"});
+  print(const Box("Deferred literal in a box!"));
+}
diff --git a/runtime/tests/vm/dart/split_literals_test.dart b/runtime/tests/vm/dart/split_literals_test.dart
new file mode 100644
index 0000000..40ecf01
--- /dev/null
+++ b/runtime/tests/vm/dart/split_literals_test.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:convert";
+import "dart:io";
+
+import "package:expect/expect.dart";
+import "package:path/path.dart" as path;
+
+import "use_flag_test_helper.dart";
+
+main(List<String> args) async {
+  if (!isAOTRuntime) {
+    return; // Running in JIT: AOT binaries not available.
+  }
+
+  if (Platform.isAndroid) {
+    return; // SDK tree not available on the test device.
+  }
+
+  // These are the tools we need to be available to run on a given platform:
+  if (!File(platformDill).existsSync()) {
+    throw "Cannot run test as $platformDill does not exist";
+  }
+  if (!await testExecutable(genSnapshot)) {
+    throw "Cannot run test as $genSnapshot not available";
+  }
+
+  sanitizedPartitioning(manifest) {
+    // Filter core libraries, relativize URIs, and sort to make the results less
+    // sensitive to compiler or test harness changes.
+    print(manifest);
+    var units = <List<String>>[];
+    for (var unit in manifest['loadingUnits']) {
+      var uris = <String>[];
+      for (var uri in unit['libraries']) {
+        if (uri.startsWith("dart:")) continue;
+        uris.add(Uri.parse(uri).pathSegments.last);
+      }
+      uris.sort((a, b) => a.compareTo(b));
+      units.add(uris);
+    }
+    units.sort((a, b) => a.first.compareTo(b.first));
+    print(units);
+    return units;
+  }
+
+  await withTempDir("split-literals-test", (String tempDir) async {
+    final source =
+        path.join(sdkDir, "runtime/tests/vm/dart_2/split_literals.dart");
+    final dill = path.join(tempDir, "split_literals.dart.dill");
+    final snapshot = path.join(tempDir, "split_literals.so");
+    final manifest = path.join(tempDir, "split_literals.txt");
+    final deferredSnapshot = snapshot + "-2.part.so";
+
+    // Compile source to kernel.
+    await run(genKernel, <String>[
+      "--aot",
+      "--platform=$platformDill",
+      "-o",
+      dill,
+      source,
+    ]);
+
+    // Compile kernel to ELF.
+    await run(genSnapshot, <String>[
+      "--use_bare_instructions=false",
+      "--snapshot-kind=app-aot-elf",
+      "--elf=$snapshot",
+      "--loading-unit-manifest=$manifest",
+      dill,
+    ]);
+    var manifestContent = jsonDecode(await new File(manifest).readAsString());
+    Expect.equals(2, manifestContent["loadingUnits"].length);
+    // Note package:expect doesn't do deep equals on collections.
+    Expect.equals(
+        "[[split_literals.dart],"
+        " [split_literals_deferred.dart]]",
+        sanitizedPartitioning(manifestContent).toString());
+    Expect.isTrue(await new File(deferredSnapshot).exists());
+
+    bool containsSubsequence(haystack, needle) {
+      outer:
+      for (var i = 0, n = haystack.length - needle.length; i < n; i++) {
+        for (var j = 0; j < needle.length; j++) {
+          if (haystack[i + j] != needle.codeUnitAt(j)) continue outer;
+        }
+        return true;
+      }
+      return false;
+    }
+
+    var unit_1 = await new File(snapshot).readAsBytes();
+    Expect.isTrue(containsSubsequence(unit_1, "Root literal!"));
+    Expect.isTrue(containsSubsequence(unit_1, "Root literal in a list!"));
+    Expect.isTrue(containsSubsequence(unit_1, "Root literal in a map!"));
+    Expect.isTrue(containsSubsequence(unit_1, "Root literal in a box!"));
+    Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal!"));
+    Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a list!"));
+    Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a map!"));
+    Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a box!"));
+
+    var unit_2 = await new File(deferredSnapshot).readAsBytes();
+    Expect.isTrue(!containsSubsequence(unit_2, "Root literal!"));
+    Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a list!"));
+    Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a map!"));
+    Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a box!"));
+    Expect.isTrue(containsSubsequence(unit_2, "Deferred literal!"));
+    Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a list!"));
+    Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a map!"));
+    Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a box!"));
+  });
+}
diff --git a/runtime/tests/vm/dart_2/regress_42067_test.dart b/runtime/tests/vm/dart_2/regress_42067_test.dart
new file mode 100644
index 0000000..21f87c8
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_42067_test.dart
@@ -0,0 +1,47 @@
+// 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.
+
+// VMOptions=--deterministic --optimization_counter_threshold=100
+
+// Verifies correct code is generated for Float64x2.fromFloat32x4 in case of
+// high register pressure.
+// Regression test for https://github.com/dart-lang/sdk/issues/42067.
+
+import 'dart:typed_data';
+
+import 'package:expect/expect.dart';
+
+@pragma('vm:never-inline')
+doTest(double x) {
+  Float32x4 a0 = Float32x4.splat(x + 1);
+  Float32x4 a1 = Float32x4.splat(x + 2);
+  Float32x4 a2 = Float32x4.splat(x + 3);
+  Float32x4 a3 = Float32x4.splat(x + 4);
+  Float32x4 a4 = Float32x4.splat(x + 5);
+  Float32x4 a5 = Float32x4.splat(x + 6);
+  Float32x4 a6 = Float32x4.splat(x + 7);
+  Float32x4 a7 = Float32x4.splat(x + 8);
+  return Float64x2.fromFloat32x4(a0) +
+      Float64x2.fromFloat32x4(a1) +
+      Float64x2.fromFloat32x4(a2) +
+      Float64x2.fromFloat32x4(a3) +
+      Float64x2.fromFloat32x4(a4) +
+      Float64x2.fromFloat32x4(a5) +
+      Float64x2.fromFloat32x4(a6) +
+      Float64x2.fromFloat32x4(a7) +
+      Float64x2.fromFloat32x4(a0) +
+      Float64x2.fromFloat32x4(a1) +
+      Float64x2.fromFloat32x4(a2) +
+      Float64x2.fromFloat32x4(a3) +
+      Float64x2.fromFloat32x4(a4) +
+      Float64x2.fromFloat32x4(a5) +
+      Float64x2.fromFloat32x4(a6) +
+      Float64x2.fromFloat32x4(a7);
+}
+
+void main() {
+  for (int i = 0; i < 200; ++i) {
+    Expect.approxEquals(88.0, doTest(1.0).x);
+  }
+}
diff --git a/runtime/tests/vm/dart_2/split_literals.dart b/runtime/tests/vm/dart_2/split_literals.dart
new file mode 100644
index 0000000..b71e9bd
--- /dev/null
+++ b/runtime/tests/vm/dart_2/split_literals.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "split_literals_deferred.dart" deferred as lib;
+
+class Box {
+  final contents;
+  const Box(this.contents);
+  String toString() => "Box($contents)";
+}
+
+main() async {
+  print("Root literal!");
+  print(const <String>["Root literal in a list!"]);
+  print(const <String, String>{"key": "Root literal in a map!"});
+  print(const Box("Root literal in a box!"));
+
+  await lib.loadLibrary();
+  lib.foo();
+}
diff --git a/runtime/tests/vm/dart_2/split_literals_deferred.dart b/runtime/tests/vm/dart_2/split_literals_deferred.dart
new file mode 100644
index 0000000..015ae1d
--- /dev/null
+++ b/runtime/tests/vm/dart_2/split_literals_deferred.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "split_literals.dart";
+
+void foo() {
+  print("Deferred literal!");
+  print(const <String>["Deferred literal in a list!"]);
+  print(const <String, String>{"key": "Deferred literal in a map!"});
+  print(const Box("Deferred literal in a box!"));
+}
diff --git a/runtime/tests/vm/dart_2/split_literals_test.dart b/runtime/tests/vm/dart_2/split_literals_test.dart
new file mode 100644
index 0000000..40ecf01
--- /dev/null
+++ b/runtime/tests/vm/dart_2/split_literals_test.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:convert";
+import "dart:io";
+
+import "package:expect/expect.dart";
+import "package:path/path.dart" as path;
+
+import "use_flag_test_helper.dart";
+
+main(List<String> args) async {
+  if (!isAOTRuntime) {
+    return; // Running in JIT: AOT binaries not available.
+  }
+
+  if (Platform.isAndroid) {
+    return; // SDK tree not available on the test device.
+  }
+
+  // These are the tools we need to be available to run on a given platform:
+  if (!File(platformDill).existsSync()) {
+    throw "Cannot run test as $platformDill does not exist";
+  }
+  if (!await testExecutable(genSnapshot)) {
+    throw "Cannot run test as $genSnapshot not available";
+  }
+
+  sanitizedPartitioning(manifest) {
+    // Filter core libraries, relativize URIs, and sort to make the results less
+    // sensitive to compiler or test harness changes.
+    print(manifest);
+    var units = <List<String>>[];
+    for (var unit in manifest['loadingUnits']) {
+      var uris = <String>[];
+      for (var uri in unit['libraries']) {
+        if (uri.startsWith("dart:")) continue;
+        uris.add(Uri.parse(uri).pathSegments.last);
+      }
+      uris.sort((a, b) => a.compareTo(b));
+      units.add(uris);
+    }
+    units.sort((a, b) => a.first.compareTo(b.first));
+    print(units);
+    return units;
+  }
+
+  await withTempDir("split-literals-test", (String tempDir) async {
+    final source =
+        path.join(sdkDir, "runtime/tests/vm/dart_2/split_literals.dart");
+    final dill = path.join(tempDir, "split_literals.dart.dill");
+    final snapshot = path.join(tempDir, "split_literals.so");
+    final manifest = path.join(tempDir, "split_literals.txt");
+    final deferredSnapshot = snapshot + "-2.part.so";
+
+    // Compile source to kernel.
+    await run(genKernel, <String>[
+      "--aot",
+      "--platform=$platformDill",
+      "-o",
+      dill,
+      source,
+    ]);
+
+    // Compile kernel to ELF.
+    await run(genSnapshot, <String>[
+      "--use_bare_instructions=false",
+      "--snapshot-kind=app-aot-elf",
+      "--elf=$snapshot",
+      "--loading-unit-manifest=$manifest",
+      dill,
+    ]);
+    var manifestContent = jsonDecode(await new File(manifest).readAsString());
+    Expect.equals(2, manifestContent["loadingUnits"].length);
+    // Note package:expect doesn't do deep equals on collections.
+    Expect.equals(
+        "[[split_literals.dart],"
+        " [split_literals_deferred.dart]]",
+        sanitizedPartitioning(manifestContent).toString());
+    Expect.isTrue(await new File(deferredSnapshot).exists());
+
+    bool containsSubsequence(haystack, needle) {
+      outer:
+      for (var i = 0, n = haystack.length - needle.length; i < n; i++) {
+        for (var j = 0; j < needle.length; j++) {
+          if (haystack[i + j] != needle.codeUnitAt(j)) continue outer;
+        }
+        return true;
+      }
+      return false;
+    }
+
+    var unit_1 = await new File(snapshot).readAsBytes();
+    Expect.isTrue(containsSubsequence(unit_1, "Root literal!"));
+    Expect.isTrue(containsSubsequence(unit_1, "Root literal in a list!"));
+    Expect.isTrue(containsSubsequence(unit_1, "Root literal in a map!"));
+    Expect.isTrue(containsSubsequence(unit_1, "Root literal in a box!"));
+    Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal!"));
+    Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a list!"));
+    Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a map!"));
+    Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a box!"));
+
+    var unit_2 = await new File(deferredSnapshot).readAsBytes();
+    Expect.isTrue(!containsSubsequence(unit_2, "Root literal!"));
+    Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a list!"));
+    Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a map!"));
+    Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a box!"));
+    Expect.isTrue(containsSubsequence(unit_2, "Deferred literal!"));
+    Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a list!"));
+    Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a map!"));
+    Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a box!"));
+  });
+}
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index ac7df11..d8c12f3 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -289,7 +289,7 @@
   ClassDeserializationCluster() : DeserializationCluster("Class") {}
   ~ClassDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     predefined_start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     intptr_t count = d->ReadUnsigned();
@@ -311,7 +311,7 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     ClassTable* table = d->isolate_group()->class_table();
 
     for (intptr_t id = predefined_start_index_; id < predefined_stop_index_;
@@ -464,7 +464,7 @@
       : DeserializationCluster("TypeArguments") {}
   ~TypeArgumentsDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -476,13 +476,13 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       TypeArgumentsPtr type_args = static_cast<TypeArgumentsPtr>(d->Ref(id));
       const intptr_t length = d->ReadUnsigned();
       Deserializer::InitializeHeader(type_args, kTypeArgumentsCid,
                                      TypeArguments::InstanceSize(length),
-                                     is_canonical);
+                                     stamp_canonical);
       type_args->ptr()->length_ = Smi::New(length);
       type_args->ptr()->hash_ = Smi::New(d->Read<int32_t>());
       type_args->ptr()->nullability_ = Smi::New(d->ReadUnsigned());
@@ -494,22 +494,15 @@
     }
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
-      CanonicalTypeArgumentsSet table(
-          d->zone(),
-          d->isolate_group()->object_store()->canonical_type_arguments());
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    if (canonicalize) {
+      Thread* thread = Thread::Current();
       TypeArguments& type_arg = TypeArguments::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         type_arg ^= refs.At(i);
-        ASSERT(type_arg.IsCanonical());
-        bool present = table.Insert(type_arg);
-        // Two recursive types with different topology (and hashes) may be
-        // equal.
-        ASSERT(!present || type_arg.IsRecursive());
+        type_arg = type_arg.Canonicalize(thread, nullptr);
+        refs.SetAt(i, type_arg);
       }
-      d->isolate_group()->object_store()->set_canonical_type_arguments(
-          table.Release());
     }
   }
 };
@@ -558,7 +551,7 @@
   PatchClassDeserializationCluster() : DeserializationCluster("PatchClass") {}
   ~PatchClassDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -569,7 +562,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       PatchClassPtr cls = static_cast<PatchClassPtr>(d->Ref(id));
       Deserializer::InitializeHeader(cls, kPatchClassCid,
@@ -667,7 +661,7 @@
   FunctionDeserializationCluster() : DeserializationCluster("Function") {}
   ~FunctionDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -677,7 +671,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     Snapshot::Kind kind = d->kind();
 
     for (intptr_t id = start_index_; id < stop_index_; id++) {
@@ -725,7 +720,7 @@
     }
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     if (d->kind() == Snapshot::kFullAOT) {
       Function& func = Function::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
@@ -816,7 +811,7 @@
   ClosureDataDeserializationCluster() : DeserializationCluster("ClosureData") {}
   ~ClosureDataDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -827,7 +822,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       ClosureDataPtr data = static_cast<ClosureDataPtr>(d->Ref(id));
       Deserializer::InitializeHeader(data, kClosureDataCid,
@@ -897,7 +893,7 @@
       : DeserializationCluster("FfiTrampolineData") {}
   ~FfiTrampolineDataDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -908,7 +904,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       FfiTrampolineDataPtr data = static_cast<FfiTrampolineDataPtr>(d->Ref(id));
       Deserializer::InitializeHeader(data, kFfiTrampolineDataCid,
@@ -920,7 +917,6 @@
   }
 };
 
-
 #if !defined(DART_PRECOMPILED_RUNTIME)
 class FieldSerializationCluster : public SerializationCluster {
  public:
@@ -1016,7 +1012,7 @@
   FieldDeserializationCluster() : DeserializationCluster("Field") {}
   ~FieldDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -1026,7 +1022,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     Snapshot::Kind kind = d->kind();
 
     for (intptr_t id = start_index_; id < stop_index_; id++) {
@@ -1067,7 +1064,7 @@
     }
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     Field& field = Field::Handle(d->zone());
     if (!IsolateGroup::Current()->use_field_guards()) {
       for (intptr_t i = start_index_; i < stop_index_; i++) {
@@ -1142,7 +1139,7 @@
   ScriptDeserializationCluster() : DeserializationCluster("Script") {}
   ~ScriptDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -1152,7 +1149,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       ScriptPtr script = static_cast<ScriptPtr>(d->Ref(id));
       Deserializer::InitializeHeader(script, kScriptCid,
@@ -1217,7 +1215,7 @@
   LibraryDeserializationCluster() : DeserializationCluster("Library") {}
   ~LibraryDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -1227,7 +1225,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       LibraryPtr lib = static_cast<LibraryPtr>(d->Ref(id));
       Deserializer::InitializeHeader(lib, kLibraryCid, Library::InstanceSize());
@@ -1289,7 +1288,7 @@
   NamespaceDeserializationCluster() : DeserializationCluster("Namespace") {}
   ~NamespaceDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -1299,7 +1298,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       NamespacePtr ns = static_cast<NamespacePtr>(d->Ref(id));
       Deserializer::InitializeHeader(ns, kNamespaceCid,
@@ -1355,7 +1355,7 @@
       : DeserializationCluster("KernelProgramInfo") {}
   ~KernelProgramInfoDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -1366,7 +1366,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       KernelProgramInfoPtr info = static_cast<KernelProgramInfoPtr>(d->Ref(id));
       Deserializer::InitializeHeader(info, kKernelProgramInfoCid,
@@ -1376,7 +1377,7 @@
     }
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     Array& array = Array::Handle(d->zone());
     KernelProgramInfo& info = KernelProgramInfo::Handle(d->zone());
     for (intptr_t id = start_index_; id < stop_index_; id++) {
@@ -1403,7 +1404,9 @@
     }
 
     if (!(s->kind() == Snapshot::kFullAOT && FLAG_use_bare_instructions)) {
-      s->Push(code->ptr()->object_pool_);
+      if (s->InCurrentLoadingUnit(code->ptr()->object_pool_)) {
+        s->Push(code->ptr()->object_pool_);
+      }
     }
     s->Push(code->ptr()->owner_);
     s->Push(code->ptr()->exception_handlers_);
@@ -1518,7 +1521,8 @@
   void WriteAlloc(Serializer* s) {
     Sort(&objects_);
     auto loading_units = s->loading_units();
-    if (loading_units != nullptr) {
+    if ((loading_units != nullptr) &&
+        (s->current_loading_unit_id() == LoadingUnit::kRootId)) {
       for (intptr_t i = LoadingUnit::kRootId + 1; i < loading_units->length();
            i++) {
         auto unit_objects = loading_units->At(i)->deferred_objects();
@@ -1590,7 +1594,11 @@
     // No need to write object pool out if we are producing full AOT
     // snapshot with bare instructions.
     if (!(kind == Snapshot::kFullAOT && FLAG_use_bare_instructions)) {
-      WriteField(code, object_pool_);
+      if (s->InCurrentLoadingUnit(code->ptr()->object_pool_)) {
+        WriteField(code, object_pool_);
+      } else {
+        WriteFieldValue(object_pool_, ObjectPool::null());
+      }
 #if defined(DART_PRECOMPILER)
     } else if (FLAG_write_v8_snapshot_profile_to != nullptr &&
                code->ptr()->object_pool_ != ObjectPool::null()) {
@@ -1716,7 +1724,7 @@
   CodeDeserializationCluster() : DeserializationCluster("Code") {}
   ~CodeDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     PageSpace* old_space = d->heap()->old_space();
     start_index_ = d->next_index();
     const intptr_t count = d->ReadUnsigned();
@@ -1734,7 +1742,8 @@
     deferred_stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       ReadFill(d, id, false);
     }
@@ -1786,7 +1795,7 @@
     code->ptr()->state_bits_ = d->Read<int32_t>();
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     d->EndInstructions(refs, start_index_, stop_index_);
 
 #if !defined(PRODUCT)
@@ -1907,7 +1916,7 @@
   ObjectPoolDeserializationCluster() : DeserializationCluster("ObjectPool") {}
   ~ObjectPoolDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -1919,7 +1928,10 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
+    fill_position_ = d->position();
+
     for (intptr_t id = start_index_; id < stop_index_; id += 1) {
       const intptr_t length = d->ReadUnsigned();
       ObjectPoolPtr pool = static_cast<ObjectPoolPtr>(d->Ref(id + 0));
@@ -1949,6 +1961,41 @@
       }
     }
   }
+
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    intptr_t restore_position = d->position();
+    d->set_position(fill_position_);
+
+    ObjectPool& pool = ObjectPool::Handle();
+    Object& entry = Object::Handle();
+    for (intptr_t id = start_index_; id < stop_index_; id += 1) {
+      pool ^= refs.At(id);
+      const intptr_t length = d->ReadUnsigned();
+      for (intptr_t j = 0; j < length; j++) {
+        const uint8_t entry_bits = d->Read<uint8_t>();
+        switch (ObjectPool::TypeBits::decode(entry_bits)) {
+          case ObjectPool::EntryType::kTaggedObject:
+            entry = refs.At(d->ReadUnsigned());
+            pool.SetObjectAt(j, entry);
+            break;
+          case ObjectPool::EntryType::kImmediate:
+            d->Read<intptr_t>();
+            break;
+          case ObjectPool::EntryType::kNativeFunction: {
+            // Read nothing.
+            break;
+          }
+          default:
+            UNREACHABLE();
+        }
+      }
+    }
+
+    d->set_position(restore_position);
+  }
+
+ private:
+  intptr_t fill_position_ = 0;
 };
 
 #if defined(DART_PRECOMPILER)
@@ -2071,7 +2118,7 @@
       : DeserializationCluster("WeakSerializationReference") {}
   ~WeakSerializationReferenceDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2085,7 +2132,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       auto const ref = static_cast<WeakSerializationReferencePtr>(d->Ref(id));
       Deserializer::InitializeHeader(
@@ -2144,7 +2192,7 @@
       : DeserializationCluster("PcDescriptors") {}
   ~PcDescriptorsDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2156,7 +2204,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id += 1) {
       const intptr_t length = d->ReadUnsigned();
       PcDescriptorsPtr desc = static_cast<PcDescriptorsPtr>(d->Ref(id));
@@ -2238,7 +2287,7 @@
       : DeserializationCluster("ROData"), cid_(cid) {}
   ~RODataDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     intptr_t count = d->ReadUnsigned();
     uint32_t running_offset = 0;
@@ -2249,21 +2298,25 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     // No-op.
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && IsStringClassId(cid_) &&
-        (d->isolate() != Dart::vm_isolate())) {
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    if (canonicalize && IsStringClassId(cid_)) {
       CanonicalStringSet table(
           d->zone(), d->isolate_group()->object_store()->symbol_table());
       String& str = String::Handle(d->zone());
+      String& str2 = String::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         str ^= refs.At(i);
-        ASSERT(str.IsCanonical());
-        bool present = table.Insert(str);
-        ASSERT(!present);
+        str2 ^= table.InsertOrGet(str);
+        if (str.raw() == str2.raw()) {
+          // str.SetCanonical();
+        } else {
+          FATAL("Lost canonicalization race");
+          refs.SetAt(i, str2);
+        }
       }
       d->isolate_group()->object_store()->set_symbol_table(table.Release());
     }
@@ -2330,7 +2383,7 @@
       : DeserializationCluster("ExceptionHandlers") {}
   ~ExceptionHandlersDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2342,7 +2395,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       ExceptionHandlersPtr handlers =
           static_cast<ExceptionHandlersPtr>(d->Ref(id));
@@ -2418,7 +2472,7 @@
   ContextDeserializationCluster() : DeserializationCluster("Context") {}
   ~ContextDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2430,7 +2484,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       ContextPtr context = static_cast<ContextPtr>(d->Ref(id));
       const intptr_t length = d->ReadUnsigned();
@@ -2495,7 +2550,7 @@
       : DeserializationCluster("ContextScope") {}
   ~ContextScopeDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2507,7 +2562,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       ContextScopePtr scope = static_cast<ContextScopePtr>(d->Ref(id));
       const intptr_t length = d->ReadUnsigned();
@@ -2563,7 +2619,7 @@
       : DeserializationCluster("UnlinkedCall") {}
   ~UnlinkedCallDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2574,7 +2630,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       UnlinkedCallPtr unlinked = static_cast<UnlinkedCallPtr>(d->Ref(id));
       Deserializer::InitializeHeader(unlinked, kUnlinkedCallCid,
@@ -2631,7 +2688,7 @@
   ICDataDeserializationCluster() : DeserializationCluster("ICData") {}
   ~ICDataDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2641,7 +2698,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       ICDataPtr ic = static_cast<ICDataPtr>(d->Ref(id));
       Deserializer::InitializeHeader(ic, kICDataCid, ICData::InstanceSize());
@@ -2696,7 +2754,7 @@
       : DeserializationCluster("MegamorphicCache") {}
   ~MegamorphicCacheDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2707,7 +2765,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       MegamorphicCachePtr cache = static_cast<MegamorphicCachePtr>(d->Ref(id));
       Deserializer::InitializeHeader(cache, kMegamorphicCacheCid,
@@ -2718,7 +2777,7 @@
   }
 
 #if defined(DART_PRECOMPILED_RUNTIME)
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     if (FLAG_use_bare_instructions) {
       // By default, every megamorphic call site will load the target
       // [Function] from the hash table and call indirectly via loading the
@@ -2787,7 +2846,7 @@
       : DeserializationCluster("SubtypeTestCache") {}
   ~SubtypeTestCacheDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2798,7 +2857,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       SubtypeTestCachePtr cache = static_cast<SubtypeTestCachePtr>(d->Ref(id));
       Deserializer::InitializeHeader(cache, kSubtypeTestCacheCid,
@@ -2850,7 +2910,7 @@
   LoadingUnitDeserializationCluster() : DeserializationCluster("LoadingUnit") {}
   ~LoadingUnitDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2861,7 +2921,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       LoadingUnitPtr unit = static_cast<LoadingUnitPtr>(d->Ref(id));
       Deserializer::InitializeHeader(unit, kLoadingUnitCid,
@@ -2920,7 +2981,7 @@
       : DeserializationCluster("LanguageError") {}
   ~LanguageErrorDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2931,7 +2992,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       LanguageErrorPtr error = static_cast<LanguageErrorPtr>(d->Ref(id));
       Deserializer::InitializeHeader(error, kLanguageErrorCid,
@@ -2987,7 +3049,7 @@
       : DeserializationCluster("UnhandledException") {}
   ~UnhandledExceptionDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -2998,7 +3060,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       UnhandledExceptionPtr exception =
           static_cast<UnhandledExceptionPtr>(d->Ref(id));
@@ -3106,13 +3169,35 @@
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class InstanceDeserializationCluster : public DeserializationCluster {
+class AbstractInstanceDeserializationCluster : public DeserializationCluster {
+ protected:
+  explicit AbstractInstanceDeserializationCluster(const char* name)
+      : DeserializationCluster(name) {}
+
+ public:
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    if (canonicalize) {
+      Thread* thread = Thread::Current();
+      SafepointMutexLocker ml(
+          thread->isolate_group()->constant_canonicalization_mutex());
+      Instance& instance = Instance::Handle(d->zone());
+      for (intptr_t i = start_index_; i < stop_index_; i++) {
+        instance ^= refs.At(i);
+        instance = instance.CanonicalizeLocked(thread);
+        refs.SetAt(i, instance);
+      }
+    }
+  }
+};
+
+class InstanceDeserializationCluster
+    : public AbstractInstanceDeserializationCluster {
  public:
   explicit InstanceDeserializationCluster(intptr_t cid)
-      : DeserializationCluster("Instance"), cid_(cid) {}
+      : AbstractInstanceDeserializationCluster("Instance"), cid_(cid) {}
   ~InstanceDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -3126,7 +3211,7 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     intptr_t next_field_offset = next_field_offset_in_words_ << kWordSizeLog2;
     intptr_t instance_size =
         Object::RoundedAllocationSize(instance_size_in_words_ * kWordSize);
@@ -3135,7 +3220,7 @@
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       InstancePtr instance = static_cast<InstancePtr>(d->Ref(id));
       Deserializer::InitializeHeader(instance, cid_, instance_size,
-                                     is_canonical);
+                                     stamp_canonical);
       intptr_t offset = Instance::NextFieldOffset();
       while (offset < next_field_offset) {
         if (unboxed_fields_bitmap.Get(offset / kWordSize)) {
@@ -3210,7 +3295,7 @@
       : DeserializationCluster("LibraryPrefix") {}
   ~LibraryPrefixDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -3221,7 +3306,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       LibraryPrefixPtr prefix = static_cast<LibraryPrefixPtr>(d->Ref(id));
       Deserializer::InitializeHeader(prefix, kLibraryPrefixCid,
@@ -3303,7 +3389,7 @@
   TypeDeserializationCluster() : DeserializationCluster("Type") {}
   ~TypeDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -3313,11 +3399,11 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       TypePtr type = static_cast<TypePtr>(d->Ref(id));
       Deserializer::InitializeHeader(type, kTypeCid, Type::InstanceSize(),
-                                     is_canonical);
+                                     stamp_canonical);
       ReadFromTo(type);
       const uint8_t combined = d->Read<uint8_t>();
       type->ptr()->type_state_ = combined >> kNullabilityBitSize;
@@ -3325,20 +3411,15 @@
     }
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
-      CanonicalTypeSet table(
-          d->zone(), d->isolate_group()->object_store()->canonical_types());
-      Type& type = Type::Handle(d->zone());
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    if (canonicalize) {
+      Thread* thread = Thread::Current();
+      AbstractType& type = AbstractType::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         type ^= refs.At(i);
-        ASSERT(type.IsCanonical());
-        bool present = table.Insert(type);
-        // Two recursive types with different topology (and hashes) may be
-        // equal.
-        ASSERT(!present || type.IsRecursive());
+        type = type.Canonicalize(thread, nullptr);
+        refs.SetAt(i, type);
       }
-      d->isolate_group()->object_store()->set_canonical_types(table.Release());
     }
 
     Type& type = Type::Handle(d->zone());
@@ -3417,7 +3498,7 @@
       : DeserializationCluster("FunctionType") {}
   ~FunctionTypeDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -3428,11 +3509,12 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       FunctionTypePtr type = static_cast<FunctionTypePtr>(d->Ref(id));
-      Deserializer::InitializeHeader(
-          type, kFunctionTypeCid, FunctionType::InstanceSize(), is_canonical);
+      Deserializer::InitializeHeader(type, kFunctionTypeCid,
+                                     FunctionType::InstanceSize(),
+                                     stamp_canonical);
       ReadFromTo(type);
       const uint8_t combined = d->Read<uint8_t>();
       type->ptr()->type_state_ = combined >> kNullabilityBitSize;
@@ -3441,22 +3523,15 @@
     }
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
-      CanonicalFunctionTypeSet table(
-          d->zone(),
-          d->isolate_group()->object_store()->canonical_function_types());
-      FunctionType& type = FunctionType::Handle(d->zone());
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    if (canonicalize) {
+      Thread* thread = Thread::Current();
+      AbstractType& type = AbstractType::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         type ^= refs.At(i);
-        ASSERT(type.IsCanonical());
-        bool present = table.Insert(type);
-        // Two recursive types with different topology (and hashes) may be
-        // equal.
-        ASSERT(!present || type.IsRecursive());
+        type = type.Canonicalize(thread, nullptr);
+        refs.SetAt(i, type);
       }
-      d->isolate_group()->object_store()->set_canonical_function_types(
-          table.Release());
     }
 
     FunctionType& type = FunctionType::Handle(d->zone());
@@ -3519,7 +3594,7 @@
   TypeRefDeserializationCluster() : DeserializationCluster("TypeRef") {}
   ~TypeRefDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -3529,16 +3604,16 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       TypeRefPtr type = static_cast<TypeRefPtr>(d->Ref(id));
-      Deserializer::InitializeHeader(type, kTypeRefCid,
-                                     TypeRef::InstanceSize());
+      Deserializer::InitializeHeader(type, kTypeRefCid, TypeRef::InstanceSize(),
+                                     stamp_canonical);
       ReadFromTo(type);
     }
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
     TypeRef& type_ref = TypeRef::Handle(d->zone());
     Code& stub = Code::Handle(d->zone());
 
@@ -3618,7 +3693,7 @@
       : DeserializationCluster("TypeParameter") {}
   ~TypeParameterDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -3629,11 +3704,12 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       TypeParameterPtr type = static_cast<TypeParameterPtr>(d->Ref(id));
-      Deserializer::InitializeHeader(
-          type, kTypeParameterCid, TypeParameter::InstanceSize(), is_canonical);
+      Deserializer::InitializeHeader(type, kTypeParameterCid,
+                                     TypeParameter::InstanceSize(),
+                                     stamp_canonical);
       ReadFromTo(type);
       type->ptr()->parameterized_class_id_ = d->Read<int32_t>();
       type->ptr()->base_ = d->Read<uint16_t>();
@@ -3644,20 +3720,15 @@
     }
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
-      CanonicalTypeParameterSet table(
-          d->zone(),
-          d->isolate_group()->object_store()->canonical_type_parameters());
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    if (canonicalize) {
+      Thread* thread = Thread::Current();
       TypeParameter& type_param = TypeParameter::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         type_param ^= refs.At(i);
-        ASSERT(type_param.IsCanonical());
-        bool present = table.Insert(type_param);
-        ASSERT(!present);
+        type_param ^= type_param.Canonicalize(thread, nullptr);
+        refs.SetAt(i, type_param);
       }
-      d->isolate_group()->object_store()->set_canonical_type_parameters(
-          table.Release());
     }
 
     TypeParameter& type_param = TypeParameter::Handle(d->zone());
@@ -3716,12 +3787,14 @@
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class ClosureDeserializationCluster : public DeserializationCluster {
+class ClosureDeserializationCluster
+    : public AbstractInstanceDeserializationCluster {
  public:
-  ClosureDeserializationCluster() : DeserializationCluster("Closure") {}
+  ClosureDeserializationCluster()
+      : AbstractInstanceDeserializationCluster("Closure") {}
   ~ClosureDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -3731,11 +3804,11 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       ClosurePtr closure = static_cast<ClosurePtr>(d->Ref(id));
       Deserializer::InitializeHeader(closure, kClosureCid,
-                                     Closure::InstanceSize(), is_canonical);
+                                     Closure::InstanceSize(), stamp_canonical);
       ReadFromTo(closure);
     }
   }
@@ -3788,7 +3861,7 @@
   MintDeserializationCluster() : DeserializationCluster("int") {}
   ~MintDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     PageSpace* old_space = d->heap()->old_space();
 
     start_index_ = d->next_index();
@@ -3801,7 +3874,7 @@
         MintPtr mint = static_cast<MintPtr>(
             AllocateUninitialized(old_space, Mint::InstanceSize()));
         Deserializer::InitializeHeader(mint, kMintCid, Mint::InstanceSize(),
-                                       is_canonical);
+                                       stamp_canonical);
         mint->ptr()->value_ = value;
         d->AssignRef(mint);
       }
@@ -3809,19 +3882,24 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {}
+  void ReadFill(Deserializer* d, bool stamp_canonical) {}
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    if (canonicalize) {
       const Class& mint_cls = Class::Handle(
-          d->zone(), IsolateGroup::Current()->object_store()->mint_class());
-      mint_cls.set_constants(Object::null_array());
+          d->zone(), d->isolate_group()->object_store()->mint_class());
       Object& number = Object::Handle(d->zone());
+      Mint& number2 = Mint::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         number = refs.At(i);
-        if (number.IsMint()) {
-          ASSERT(number.IsCanonical());
+        if (!number.IsMint()) continue;
+        number2 =
+            mint_cls.LookupCanonicalMint(d->zone(), Mint::Cast(number).value());
+        if (number2.IsNull()) {
+          number.SetCanonical();
           mint_cls.InsertCanonicalMint(d->zone(), Mint::Cast(number));
+        } else {
+          refs.SetAt(i, number2);
         }
       }
     }
@@ -3868,7 +3946,7 @@
   DoubleDeserializationCluster() : DeserializationCluster("double") {}
   ~DoubleDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -3878,14 +3956,35 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       DoublePtr dbl = static_cast<DoublePtr>(d->Ref(id));
       Deserializer::InitializeHeader(dbl, kDoubleCid, Double::InstanceSize(),
-                                     is_canonical);
+                                     stamp_canonical);
       dbl->ptr()->value_ = d->Read<double>();
     }
   }
+
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    if (canonicalize) {
+      const Class& cls = Class::Handle(
+          d->zone(), d->isolate_group()->object_store()->double_class());
+      SafepointMutexLocker ml(
+          d->isolate_group()->constant_canonicalization_mutex());
+      Double& dbl = Double::Handle(d->zone());
+      Double& dbl2 = Double::Handle(d->zone());
+      for (intptr_t i = start_index_; i < stop_index_; i++) {
+        dbl ^= refs.At(i);
+        dbl2 = cls.LookupCanonicalDouble(d->zone(), dbl.value());
+        if (dbl2.IsNull()) {
+          dbl.SetCanonical();
+          cls.InsertCanonicalDouble(d->zone(), dbl);
+        } else {
+          refs.SetAt(i, dbl2);
+        }
+      }
+    }
+  }
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -3932,7 +4031,7 @@
       : DeserializationCluster("GrowableObjectArray") {}
   ~GrowableObjectArrayDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -3943,13 +4042,13 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       GrowableObjectArrayPtr list =
           static_cast<GrowableObjectArrayPtr>(d->Ref(id));
       Deserializer::InitializeHeader(list, kGrowableObjectArrayCid,
                                      GrowableObjectArray::InstanceSize(),
-                                     is_canonical);
+                                     stamp_canonical);
       ReadFromTo(list);
     }
   }
@@ -4005,7 +4104,7 @@
       : DeserializationCluster("TypedData"), cid_(cid) {}
   ~TypedDataDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -4018,15 +4117,17 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     intptr_t element_size = TypedData::ElementSizeInBytes(cid_);
 
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       TypedDataPtr data = static_cast<TypedDataPtr>(d->Ref(id));
       const intptr_t length = d->ReadUnsigned();
       const intptr_t length_in_bytes = length * element_size;
-      Deserializer::InitializeHeader(
-          data, cid_, TypedData::InstanceSize(length_in_bytes), is_canonical);
+      Deserializer::InitializeHeader(data, cid_,
+                                     TypedData::InstanceSize(length_in_bytes),
+                                     stamp_canonical);
       data->ptr()->length_ = Smi::New(length);
       data->ptr()->RecomputeDataField();
       uint8_t* cdata = reinterpret_cast<uint8_t*>(data->ptr()->data());
@@ -4083,7 +4184,7 @@
       : DeserializationCluster("TypedDataView"), cid_(cid) {}
   ~TypedDataViewDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -4094,16 +4195,17 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       TypedDataViewPtr view = static_cast<TypedDataViewPtr>(d->Ref(id));
-      Deserializer::InitializeHeader(view, cid_, TypedDataView::InstanceSize(),
-                                     is_canonical);
+      Deserializer::InitializeHeader(view, cid_, TypedDataView::InstanceSize());
       ReadFromTo(view);
     }
   }
 
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    ASSERT(!canonicalize);
     auto& view = TypedDataView::Handle(d->zone());
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       view ^= refs.At(id);
@@ -4163,7 +4265,7 @@
       : DeserializationCluster("ExternalTypedData"), cid_(cid) {}
   ~ExternalTypedDataDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -4174,7 +4276,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     intptr_t element_size = ExternalTypedData::ElementSizeInBytes(cid_);
 
     for (intptr_t id = start_index_; id < stop_index_; id++) {
@@ -4235,7 +4338,7 @@
   StackTraceDeserializationCluster() : DeserializationCluster("StackTrace") {}
   ~StackTraceDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -4246,7 +4349,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       StackTracePtr trace = static_cast<StackTracePtr>(d->Ref(id));
       Deserializer::InitializeHeader(trace, kStackTraceCid,
@@ -4300,7 +4404,7 @@
   RegExpDeserializationCluster() : DeserializationCluster("RegExp") {}
   ~RegExpDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -4310,7 +4414,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       RegExpPtr regexp = static_cast<RegExpPtr>(d->Ref(id));
       Deserializer::InitializeHeader(regexp, kRegExpCid,
@@ -4365,7 +4470,7 @@
       : DeserializationCluster("WeakProperty") {}
   ~WeakPropertyDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -4376,7 +4481,8 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
+    ASSERT(!stamp_canonical);  // Never canonical.
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       WeakPropertyPtr property = static_cast<WeakPropertyPtr>(d->Ref(id));
       Deserializer::InitializeHeader(property, kWeakPropertyCid,
@@ -4455,13 +4561,14 @@
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class LinkedHashMapDeserializationCluster : public DeserializationCluster {
+class LinkedHashMapDeserializationCluster
+    : public AbstractInstanceDeserializationCluster {
  public:
   LinkedHashMapDeserializationCluster()
-      : DeserializationCluster("LinkedHashMap") {}
+      : AbstractInstanceDeserializationCluster("LinkedHashMap") {}
   ~LinkedHashMapDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -4472,13 +4579,14 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     PageSpace* old_space = d->heap()->old_space();
 
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       LinkedHashMapPtr map = static_cast<LinkedHashMapPtr>(d->Ref(id));
-      Deserializer::InitializeHeader(
-          map, kLinkedHashMapCid, LinkedHashMap::InstanceSize(), is_canonical);
+      Deserializer::InitializeHeader(map, kLinkedHashMapCid,
+                                     LinkedHashMap::InstanceSize(),
+                                     stamp_canonical);
 
       map->ptr()->type_arguments_ = static_cast<TypeArgumentsPtr>(d->ReadRef());
 
@@ -4561,13 +4669,14 @@
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class ArrayDeserializationCluster : public DeserializationCluster {
+class ArrayDeserializationCluster
+    : public AbstractInstanceDeserializationCluster {
  public:
   explicit ArrayDeserializationCluster(intptr_t cid)
-      : DeserializationCluster("Array"), cid_(cid) {}
+      : AbstractInstanceDeserializationCluster("Array"), cid_(cid) {}
   ~ArrayDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -4579,12 +4688,12 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       ArrayPtr array = static_cast<ArrayPtr>(d->Ref(id));
       const intptr_t length = d->ReadUnsigned();
       Deserializer::InitializeHeader(array, cid_, Array::InstanceSize(length),
-                                     is_canonical);
+                                     stamp_canonical);
       array->ptr()->type_arguments_ =
           static_cast<TypeArgumentsPtr>(d->ReadRef());
       array->ptr()->length_ = Smi::New(length);
@@ -4639,13 +4748,40 @@
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class OneByteStringDeserializationCluster : public DeserializationCluster {
+class StringDeserializationCluster : public DeserializationCluster {
+ protected:
+  explicit StringDeserializationCluster(const char* name)
+      : DeserializationCluster(name) {}
+
+ public:
+  void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+    if (canonicalize) {
+      CanonicalStringSet table(
+          d->zone(), d->isolate_group()->object_store()->symbol_table());
+      String& str = String::Handle(d->zone());
+      String& str2 = String::Handle(d->zone());
+      for (intptr_t i = start_index_; i < stop_index_; i++) {
+        str ^= refs.At(i);
+        str2 ^= table.InsertOrGet(str);
+        if (str.raw() == str2.raw()) {
+          str.SetCanonical();
+        } else {
+          refs.SetAt(i, str2);
+        }
+      }
+      d->isolate_group()->object_store()->set_symbol_table(table.Release());
+    }
+  }
+};
+
+class OneByteStringDeserializationCluster
+    : public StringDeserializationCluster {
  public:
   OneByteStringDeserializationCluster()
-      : DeserializationCluster("OneByteString") {}
+      : StringDeserializationCluster("OneByteString") {}
   ~OneByteStringDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -4657,13 +4793,13 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       OneByteStringPtr str = static_cast<OneByteStringPtr>(d->Ref(id));
       const intptr_t length = d->ReadUnsigned();
       Deserializer::InitializeHeader(str, kOneByteStringCid,
                                      OneByteString::InstanceSize(length),
-                                     is_canonical);
+                                     stamp_canonical);
       str->ptr()->length_ = Smi::New(length);
       StringHasher hasher;
       for (intptr_t j = 0; j < length; j++) {
@@ -4674,21 +4810,6 @@
       String::SetCachedHash(str, hasher.Finalize());
     }
   }
-
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
-      CanonicalStringSet table(
-          d->zone(), d->isolate_group()->object_store()->symbol_table());
-      String& str = String::Handle(d->zone());
-      for (intptr_t i = start_index_; i < stop_index_; i++) {
-        str ^= refs.At(i);
-        ASSERT(str.IsCanonical());
-        bool present = table.Insert(str);
-        ASSERT(!present);
-      }
-      d->isolate_group()->object_store()->set_symbol_table(table.Release());
-    }
-  }
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -4732,13 +4853,14 @@
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class TwoByteStringDeserializationCluster : public DeserializationCluster {
+class TwoByteStringDeserializationCluster
+    : public StringDeserializationCluster {
  public:
   TwoByteStringDeserializationCluster()
-      : DeserializationCluster("TwoByteString") {}
+      : StringDeserializationCluster("TwoByteString") {}
   ~TwoByteStringDeserializationCluster() {}
 
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
+  void ReadAlloc(Deserializer* d, bool stamp_canonical) {
     start_index_ = d->next_index();
     PageSpace* old_space = d->heap()->old_space();
     const intptr_t count = d->ReadUnsigned();
@@ -4750,13 +4872,13 @@
     stop_index_ = d->next_index();
   }
 
-  void ReadFill(Deserializer* d, bool is_canonical) {
+  void ReadFill(Deserializer* d, bool stamp_canonical) {
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       TwoByteStringPtr str = static_cast<TwoByteStringPtr>(d->Ref(id));
       const intptr_t length = d->ReadUnsigned();
       Deserializer::InitializeHeader(str, kTwoByteStringCid,
                                      TwoByteString::InstanceSize(length),
-                                     is_canonical);
+                                     stamp_canonical);
       str->ptr()->length_ = Smi::New(length);
       StringHasher hasher;
       for (intptr_t j = 0; j < length; j++) {
@@ -4768,21 +4890,6 @@
       String::SetCachedHash(str, hasher.Finalize());
     }
   }
-
-  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
-      CanonicalStringSet table(
-          d->zone(), d->isolate_group()->object_store()->symbol_table());
-      String& str = String::Handle(d->zone());
-      for (intptr_t i = start_index_; i < stop_index_; i++) {
-        str ^= refs.At(i);
-        ASSERT(str.IsCanonical());
-        bool present = table.Insert(str);
-        ASSERT(!present);
-      }
-      d->isolate_group()->object_store()->set_symbol_table(table.Release());
-    }
-  }
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -5162,6 +5269,9 @@
       const Object* deferred_object = (*unit_->deferred_objects())[i];
       ASSERT(deferred_object->IsCode());
       CodePtr code = static_cast<CodePtr>(deferred_object->raw());
+      if (!FLAG_use_bare_instructions) {
+        s->Push(code->ptr()->object_pool_);
+      }
       s->Push(code->ptr()->compressed_stackmaps_);
       s->Push(code->ptr()->code_source_map_);
     }
@@ -5191,6 +5301,9 @@
       ASSERT(s->RefId(code) == (start_index + i));
       s->WriteInstructions(code->ptr()->instructions_,
                            code->ptr()->unchecked_offset_, code, false);
+      if (!FLAG_use_bare_instructions) {
+        s->WriteRootRef(code->ptr()->object_pool_, "deferred-code");
+      }
       s->WriteRootRef(code->ptr()->compressed_stackmaps_, "deferred-code");
       s->WriteRootRef(code->ptr()->code_source_map_, "deferred-code");
     }
@@ -5229,10 +5342,19 @@
         ASSERT(unchecked_entry_point != 0);
         func->ptr()->unchecked_entry_point_ = unchecked_entry_point;
       }
+      if (!FLAG_use_bare_instructions) {
+        code->ptr()->object_pool_ = static_cast<ObjectPoolPtr>(d->ReadRef());
+      }
       code->ptr()->compressed_stackmaps_ =
           static_cast<CompressedStackMapsPtr>(d->ReadRef());
       code->ptr()->code_source_map_ =
           static_cast<CodeSourceMapPtr>(d->ReadRef());
+
+      // TODO(rmacnak): Should we finalize any pending GC before deserializing
+      // instead?
+      if (d->thread()->is_marking()) {
+        d->thread()->DeferredMarkingStackAddObject(code);
+      }
     }
 
     // Reinitialize the dispatch table by rereading the table's serialization
@@ -5647,6 +5769,9 @@
     // TODO(41974): Are these always type testing stubs?
     unit_id = LoadingUnit::kRootId;
   }
+  if (unit_id == LoadingUnit::kRootId) {
+    return true;
+  }
   if (unit_id != current_loading_unit_id_) {
     if (record) {
       (*loading_units_)[unit_id]->AddDeferredObject(static_cast<CodePtr>(obj));
@@ -5869,6 +5994,22 @@
   }
 
   GrowableArray<SerializationCluster*> canonical_clusters;
+  // The order that PostLoad runs matters for some classes. Explicitly place
+  // these clusters first, then add the rest ordered by class id.
+#define ADD_NEXT(cid)                                                          \
+  if (canonical_clusters_by_cid_[cid] != nullptr) {                            \
+    canonical_clusters.Add(canonical_clusters_by_cid_[cid]);                   \
+    canonical_clusters_by_cid_[cid] = nullptr;                                 \
+  }
+  ADD_NEXT(kOneByteStringCid)
+  ADD_NEXT(kTwoByteStringCid)
+  ADD_NEXT(kMintCid)
+  ADD_NEXT(kDoubleCid)
+  ADD_NEXT(kTypeParameterCid)
+  ADD_NEXT(kTypeCid)
+  ADD_NEXT(kTypeArgumentsCid)
+  ADD_NEXT(kClosureCid)
+#undef ADD_NEXT
   for (intptr_t cid = 0; cid < num_cids_; cid++) {
     if (canonical_clusters_by_cid_[cid] != nullptr) {
       canonical_clusters.Add(canonical_clusters_by_cid_[cid]);
@@ -6690,18 +6831,17 @@
     ASSERT_EQUAL(next_ref_index_ - kFirstReference, num_objects_);
 
     {
-      TIMELINE_DURATION(thread(), Isolate, "ReadFill");
+      TIMELINE_DURATION(thread(), Isolate, "PostLoad");
       for (intptr_t i = 0; i < num_canonical_clusters_; i++) {
-        TIMELINE_DURATION(thread(), Isolate, canonical_clusters_[i]->name());
-        canonical_clusters_[i]->ReadFill(this, /*is_canonical*/ true);
+        bool stamp_canonical = isolate() == Dart::vm_isolate();
+        canonical_clusters_[i]->ReadFill(this, stamp_canonical);
 #if defined(DEBUG)
         int32_t section_marker = Read<int32_t>();
         ASSERT(section_marker == kSectionMarker);
 #endif
       }
       for (intptr_t i = 0; i < num_clusters_; i++) {
-        TIMELINE_DURATION(thread(), Isolate, clusters_[i]->name());
-        clusters_[i]->ReadFill(this, /*is_canonical*/ false);
+        clusters_[i]->ReadFill(this, /*stamp_canonical*/ false);
 #if defined(DEBUG)
         int32_t section_marker = Read<int32_t>();
         ASSERT(section_marker == kSectionMarker);
@@ -6723,26 +6863,22 @@
   roots->PostLoad(this, refs);
 
 #if defined(DEBUG)
-  Isolate* isolate = thread()->isolate();
-  isolate->ValidateClassTable();
-  if (isolate != Dart::vm_isolate()) {
-    isolate->group()->heap()->Verify();
+  isolate()->ValidateClassTable();
+  if (isolate() != Dart::vm_isolate()) {
+    isolate_group()->heap()->Verify();
   }
 #endif
 
-  // TODO(rmacnak): When splitting literals, load clusters requiring
-  // canonicalization first, canonicalize and update the ref array, the load
-  // the remaining clusters to avoid a full heap walk to update references to
-  // the losers of any canonicalization races.
   {
     TIMELINE_DURATION(thread(), Isolate, "PostLoad");
     for (intptr_t i = 0; i < num_canonical_clusters_; i++) {
       TIMELINE_DURATION(thread(), Isolate, canonical_clusters_[i]->name());
-      canonical_clusters_[i]->PostLoad(this, refs, /*is_canonical*/ true);
+      bool canonicalize = isolate() != Dart::vm_isolate();
+      canonical_clusters_[i]->PostLoad(this, refs, canonicalize);
     }
     for (intptr_t i = 0; i < num_clusters_; i++) {
       TIMELINE_DURATION(thread(), Isolate, clusters_[i]->name());
-      clusters_[i]->PostLoad(this, refs, /*is_canonical*/ false);
+      clusters_[i]->PostLoad(this, refs, /*canonicalize*/ false);
     }
   }
 }
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 07a7b1e..d3471b6 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -116,16 +116,20 @@
 
   // Allocate memory for all objects in the cluster and write their addresses
   // into the ref array. Do not touch this memory.
-  virtual void ReadAlloc(Deserializer* deserializer, bool is_canonical) = 0;
+  virtual void ReadAlloc(Deserializer* deserializer, bool stamp_canonical) = 0;
 
   // Initialize the cluster's objects. Do not touch the memory of other objects.
-  virtual void ReadFill(Deserializer* deserializer, bool is_canonical) = 0;
+  virtual void ReadFill(Deserializer* deserializer, bool stamp_canonical) = 0;
 
   // Complete any action that requires the full graph to be deserialized, such
   // as rehashing.
   virtual void PostLoad(Deserializer* deserializer,
                         const Array& refs,
-                        bool is_canonical) {}
+                        bool canonicalize) {
+    if (canonicalize) {
+      FATAL1("%s needs canonicalization but doesn't define PostLoad", name());
+    }
+  }
 
   const char* name() const { return name_; }
 
@@ -380,6 +384,7 @@
   void set_loading_units(GrowableArray<LoadingUnitSerializationData*>* units) {
     loading_units_ = units;
   }
+  intptr_t current_loading_unit_id() { return current_loading_unit_id_; }
   void set_current_loading_unit_id(intptr_t id) {
     current_loading_unit_id_ = id;
   }
@@ -573,6 +578,8 @@
 
   uword ReadWordWith32BitReads() { return stream_.ReadWordWith32BitReads(); }
 
+  intptr_t position() const { return stream_.Position(); }
+  void set_position(intptr_t p) { stream_.SetPosition(p); }
   const uint8_t* CurrentBufferAddress() const {
     return stream_.AddressOfCurrentPosition();
   }
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 5ff3ed1..e354b26 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -5530,9 +5530,9 @@
   __ vcvtsd(r.s(1), q.d(1));
 }
 
-// Low (< 7) Q registers are needed for the vcvtsd instruction.
+// Low (< 7) Q registers are needed for the vcvtds instruction.
 // TODO(dartbug.com/30953) support register range constraints in the regalloc.
-DEFINE_EMIT(Float32x4ToFloat64x2, (FixedQRegisterView<Q6> r, QRegisterView q)) {
+DEFINE_EMIT(Float32x4ToFloat64x2, (QRegisterView r, FixedQRegisterView<Q6> q)) {
   // Set X.
   __ vcvtds(r.d(0), q.s(0));
   // Set Y.
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index eb7276a..30ae528 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -86,7 +86,7 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    52;
+    48;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
     88;
 static constexpr dart::compiler::target::word Class_super_type_offset = 44;
@@ -611,7 +611,7 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    104;
+    96;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
     164;
 static constexpr dart::compiler::target::word Class_super_type_offset = 88;
@@ -1140,7 +1140,7 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    52;
+    48;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
     88;
 static constexpr dart::compiler::target::word Class_super_type_offset = 44;
@@ -1662,7 +1662,7 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    104;
+    96;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
     164;
 static constexpr dart::compiler::target::word Class_super_type_offset = 88;
@@ -2194,7 +2194,7 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    52;
+    48;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
     88;
 static constexpr dart::compiler::target::word Class_super_type_offset = 44;
@@ -2713,7 +2713,7 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    104;
+    96;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
     164;
 static constexpr dart::compiler::target::word Class_super_type_offset = 88;
@@ -3236,7 +3236,7 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    52;
+    48;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
     88;
 static constexpr dart::compiler::target::word Class_super_type_offset = 44;
@@ -3752,7 +3752,7 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    104;
+    96;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
     164;
 static constexpr dart::compiler::target::word Class_super_type_offset = 88;
@@ -4280,7 +4280,7 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 52;
+    AOT_Class_declaration_type_offset = 48;
 static constexpr dart::compiler::target::word
     AOT_Class_num_type_arguments_offset = 88;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 44;
@@ -4864,7 +4864,7 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 104;
+    AOT_Class_declaration_type_offset = 96;
 static constexpr dart::compiler::target::word
     AOT_Class_num_type_arguments_offset = 164;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
@@ -5454,7 +5454,7 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 104;
+    AOT_Class_declaration_type_offset = 96;
 static constexpr dart::compiler::target::word
     AOT_Class_num_type_arguments_offset = 164;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
@@ -6043,7 +6043,7 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 52;
+    AOT_Class_declaration_type_offset = 48;
 static constexpr dart::compiler::target::word
     AOT_Class_num_type_arguments_offset = 88;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 44;
@@ -6620,7 +6620,7 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 104;
+    AOT_Class_declaration_type_offset = 96;
 static constexpr dart::compiler::target::word
     AOT_Class_num_type_arguments_offset = 164;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
@@ -7203,7 +7203,7 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 104;
+    AOT_Class_declaration_type_offset = 96;
 static constexpr dart::compiler::target::word
     AOT_Class_num_type_arguments_offset = 164;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
diff --git a/runtime/vm/instructions_arm64.cc b/runtime/vm/instructions_arm64.cc
index 80ee77a..1ebd214 100644
--- a/runtime/vm/instructions_arm64.cc
+++ b/runtime/vm/instructions_arm64.cc
@@ -53,8 +53,8 @@
       native_function_pool_index_(-1),
       target_code_pool_index_(-1) {
   ASSERT(code.ContainsInstructionAt(pc));
-  // Last instruction: blr ip0.
-  ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200);
+  // Last instruction: blr lr.
+  ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f03c0);
 
   Register reg;
   uword native_function_load_end = InstructionPattern::DecodeLoadWordFromPool(
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 36a2155..a220f97 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -20132,9 +20132,11 @@
       }
     }
     ASSERT(this->Equals(type));
-    ASSERT(type.IsCanonical());
-    ASSERT(type.IsOld());
-    return type.raw();
+    // TODO(rmacnak): Revisit immediately returning type after to changes to
+    // recanonicalization on load for literal splitting.
+    if (type.IsCanonical()) {
+      return type.raw();
+    }
   }
 
   Type& type = Type::Handle(zone);
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index aecd13b..6e81fb3 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -1371,9 +1371,15 @@
     MergeAssignment(obj_, id);
     obj_ = code.compressed_stackmaps();
     MergeAssignment(obj_, id);
+    if (!FLAG_use_bare_instructions) {
+      obj_ = code.object_pool();
+      MergeAssignment(obj_, id);
+    }
   }
 
   void MergeAssignment(const Object& obj, intptr_t id) {
+    if (obj.IsNull()) return;
+
     intptr_t old_id = heap_->GetLoadingUnit(obj_.raw());
     if (old_id == WeakTable::kNoValue) {
       heap_->SetLoadingUnit(obj_.raw(), id);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 06e736a..5b4a2fd 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -819,8 +819,6 @@
   POINTER_FIELD(LibraryPtr, library)
   POINTER_FIELD(TypeArgumentsPtr, type_parameters)  // Array of TypeParameter.
   POINTER_FIELD(AbstractTypePtr, super_type)
-  POINTER_FIELD(ArrayPtr,
-                constants)  // Canonicalized const instances of this class.
   POINTER_FIELD(TypePtr, declaration_type)  // Declaration type for this class.
   POINTER_FIELD(ArrayPtr,
                 invocation_dispatcher_cache)  // Cache for dispatcher functions.
@@ -830,7 +828,9 @@
                 direct_implementors)                        // Array of Class.
   POINTER_FIELD(GrowableObjectArrayPtr, direct_subclasses)  // Array of Class.
   POINTER_FIELD(ArrayPtr, dependent_code)  // CHA optimized codes.
-  VISIT_TO(ObjectPtr, dependent_code)
+  POINTER_FIELD(ArrayPtr,
+                constants)  // Canonicalized const instances of this class.
+  VISIT_TO(ObjectPtr, constants)
   ObjectPtr* to_snapshot(Snapshot::Kind kind) {
     switch (kind) {
       case Snapshot::kFullAOT:
diff --git a/tests/dart2js/native/bound_closure_super_test.dart b/tests/dart2js/native/bound_closure_super_test.dart
deleted file mode 100644
index d97d8e1..0000000
--- a/tests/dart2js/native/bound_closure_super_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2013, 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.
-
-// Test calling convention of property extraction closures (super edition).
-library bound_closure_super_test;
-
-import 'package:expect/expect.dart';
-
-import 'bound_closure_test.dart' as bound_closure_test;
-
-import 'bound_closure_test.dart' show inscrutable, makeCC;
-
-main() {
-  // Calling main from bound_closure_test.dart to set up native code.
-  bound_closure_test.main();
-
-  var c = inscrutable(makeCC)();
-  var csfoo = inscrutable(c).superfoo;
-
-  Expect.equals('BB.foo(1, B)', csfoo(1));
-  Expect.equals('BB.foo(2, 3)', csfoo(2, 3));
-}
diff --git a/tests/dart2js_2/native/bound_closure_super_test.dart b/tests/dart2js_2/native/bound_closure_super_test.dart
deleted file mode 100644
index 67c36ed..0000000
--- a/tests/dart2js_2/native/bound_closure_super_test.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.7
-
-// Test calling convention of property extraction closures (super edition).
-library bound_closure_super_test;
-
-import 'package:expect/expect.dart';
-
-import 'bound_closure_test.dart' as bound_closure_test;
-
-import 'bound_closure_test.dart' show inscrutable, makeCC;
-
-main() {
-  // Calling main from bound_closure_test.dart to set up native code.
-  bound_closure_test.main();
-
-  var c = inscrutable(makeCC)();
-  var csfoo = inscrutable(c).superfoo;
-
-  Expect.equals('BB.foo(1, B)', csfoo(1));
-  Expect.equals('BB.foo(2, 3)', csfoo(2, 3));
-}
diff --git a/tests/language/nnbd/flow_analysis/boolean_parameter_test.dart b/tests/language/nnbd/flow_analysis/boolean_parameter_test.dart
new file mode 100644
index 0000000..e0f753c
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/boolean_parameter_test.dart
@@ -0,0 +1,141 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks whether a function parameter can be used to perform type
+// promotion, for various ways of declaring it.
+//
+// We test all combinations of:
+// - top level function, method, local named function, or function expression
+// - type `bool`, `Object`, `Object?`, or `dynamic`
+
+topLevelFunction_bool(int? x, bool b) {
+  b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+topLevelFunction_Object(int? x, Object b) {
+  b = x != null;
+  // We don't currently recognize that `b as bool` has the same value as `b`,
+  // so we don't promote.  TODO(paulberry): should we?
+  if (b as bool) x.expectStaticType<Exactly<int?>>();
+}
+
+topLevelFunction_ObjectQ(int? x, Object? b) {
+  b = x != null;
+  // We don't currently recognize that `b as bool` has the same value as `b`,
+  // so we don't promote.  TODO(paulberry): should we?
+  if (b as bool) x.expectStaticType<Exactly<int?>>();
+}
+
+topLevelFunction_dynamic(int? x, dynamic b) {
+  b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+class C {
+  method_bool(int? x, bool b) {
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+
+  method_Object(int? x, Object b) {
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+
+  method_ObjectQ(int? x, Object? b) {
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+
+  method_dynamic(int? x, dynamic b) {
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+}
+
+localTest(int? x) {
+  localNamedFunction_bool(bool b) {
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+
+  localNamedFunction_bool(false);
+
+  localNamedFunction_Object(Object b) {
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+
+  localNamedFunction_Object(Object());
+
+  localNamedFunction_ObjectQ(Object? b) {
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+
+  localNamedFunction_ObjectQ(null);
+
+  localNamedFunction_dynamic(dynamic b) {
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+
+  localNamedFunction_dynamic('foo');
+
+  (bool b) {
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }(false);
+
+  (Object b) {
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }(Object());
+
+  (Object? b) {
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }(null);
+
+  (dynamic b) {
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }('foo');
+}
+
+main() {
+  topLevelFunction_bool(null, false);
+  topLevelFunction_bool(0, false);
+  topLevelFunction_Object(null, Object());
+  topLevelFunction_Object(0, Object());
+  topLevelFunction_ObjectQ(null, null);
+  topLevelFunction_ObjectQ(0, null);
+  topLevelFunction_dynamic(null, 'foo');
+  topLevelFunction_dynamic(0, 'foo');
+  C().method_bool(null, false);
+  C().method_bool(0, false);
+  C().method_Object(null, Object());
+  C().method_Object(0, Object());
+  C().method_ObjectQ(null, null);
+  C().method_ObjectQ(0, null);
+  C().method_dynamic(null, 'foo');
+  C().method_dynamic(0, 'foo');
+  localTest(null);
+  localTest(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_compound_assignment_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_compound_assignment_test.dart
new file mode 100644
index 0000000..b76b066
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_compound_assignment_test.dart
@@ -0,0 +1,251 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks that local boolean variables cannot be used to perform type
+// promotion in the presence of compound assignments.
+//
+// We test the following kinds of compound assignments:
+// - Ordinary (e.g. `+=`)
+// - Prefix increment/decrement (e.g. `++<variable>`)
+// - Postfix increment/decrement (e.g. `<variable>++`)
+// - Null-aware (`??=`)
+//
+// We test both the side effect of the assignment and the evaluated value of the
+// assignment expression.
+
+testSideEffect(int? x) {
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b /= x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b ~/= x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b %= x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b += x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b -= x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b <<= x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b >>= x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b &= x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b ^= x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b |= x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b ??= x != null;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ++b;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    --b;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b++;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b--;
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+}
+
+testValue(int? x) {
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b /= x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b ~/= x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b %= x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b += x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b -= x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b <<= x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b >>= x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b &= x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b ^= x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b |= x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b ??= x != null) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (++b) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (--b) {
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b++) {
+      // Note: arguably we could promote here (since the value of `b++` is the
+      // same as the value that `b` had before the "increment") but given that
+      // incrementing booleans doesn't work at runtime anyhow, it doesn't seem
+      // worth it.
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    if (b--) {
+      // Note: arguably we could promote here (since the value of `b--` is the
+      // same as the value that `b` had before the "decrement") but given that
+      // decrementing booleans doesn't work at runtime anyhow, it doesn't seem
+      // worth it.
+      x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+}
+
+bool _alwaysFalse() => false;
+
+main() {
+  // Because of the use of dynamic in these tests, they're not expected to
+  // succeed at runtime; we just want to check the compile-time behavior.  So we
+  // reference the test functions but don't call them.
+  if (_alwaysFalse()) testSideEffect(0);
+  if (_alwaysFalse()) testValue(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_assignment_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_assignment_test.dart
new file mode 100644
index 0000000..649155a
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_assignment_test.dart
@@ -0,0 +1,642 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks various scenarios in which the use of a local variable for
+// type promotion is defeated, either by an assignment to the local variable
+// itself or an assignment to the variable that would be promoted.
+
+direct_toConditionVar(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  b = true;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+direct_toPromotedVar(int? x, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  x = y;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+lateInitializer_toConditionalVar(int? x) {
+  bool b = x != null;
+  late final y = b ? x.expectStaticType<Exactly<int?>>() : 3;
+  b = true;
+}
+
+lateInitializer_toPromotedVar(int? x, int? y) {
+  bool b = x != null;
+  late final y = b ? x.expectStaticType<Exactly<int?>>() : 3;
+  x = y;
+}
+
+afterConditionalThen_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  b2 ? b = true : null;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterConditionalThen_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  b2 ? x = y : null;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterConditionalElse_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  b2 ? null : b = true;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterConditionalElse_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  b2 ? null : x = y;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfStatementThen_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  if (b2) b = true;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfStatementThen_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  if (b2) x = y;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfStatementElse_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  if (b2) {
+  } else {
+    b = true;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfStatementElse_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  if (b2) {
+  } else {
+    x = y;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfListThen_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  [if (b2) b = true];
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfListThen_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  [if (b2) x = y];
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfListElse_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  [if (b2) null else b = true];
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfListElse_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  [if (b2) null else x = y];
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfSetThen_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) b = true});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfSetThen_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) x = y});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfSetElse_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) null else b = true});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfSetElse_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) null else x = y});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapKeyThen_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) b = true: null});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapKeyThen_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) x = y: null});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapKeyElse_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) null: null else b = true: null});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapKeyElse_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) null: null else x = y: null});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapValueThen_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) null: b = true});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapValueThen_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) null: x = y});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapValueElse_toConditionVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) null: null else null: b = true});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapValueElse_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  ({if (b2) null: null else null: x = y});
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+doLater_toConditionalVar(int? x, int i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  do {
+    if (b) x.expectStaticType<Exactly<int?>>();
+    b = true;
+  } while (i-- > 0);
+}
+
+doLater_toPromotedVar(int? x, int i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  do {
+    if (b) x.expectStaticType<Exactly<int?>>();
+    x = y;
+  } while (i-- > 0);
+}
+
+forLater_toConditionalVar(int? x, int i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  for (int j = 0; j < i; j++) {
+    if (b) x.expectStaticType<Exactly<int?>>();
+    b = true;
+  }
+}
+
+forLater_toPromotedVar(int? x, int i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  for (int j = 0; j < i; j++) {
+    if (b) x.expectStaticType<Exactly<int?>>();
+    x = y;
+  }
+}
+
+forEachLater_toConditionalVar(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  for (var v in [null]) {
+    if (b) x.expectStaticType<Exactly<int?>>();
+    b = true;
+  }
+}
+
+forEachLater_toPromotedVar(int? x, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  for (var v in [null]) {
+    if (b) x.expectStaticType<Exactly<int?>>();
+    x = y;
+  }
+}
+
+whileLater_toConditionalVar(int? x, int i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  while (i-- > 0) {
+    if (b) x.expectStaticType<Exactly<int?>>();
+    b = true;
+  }
+}
+
+whileLater_toPromotedVar(int? x, int i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  while (i-- > 0) {
+    if (b) x.expectStaticType<Exactly<int?>>();
+    x = y;
+  }
+}
+
+switchLaterLabeled_toConditionalVar(int? x, int i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  switch (i) {
+    L:
+    case 0:
+      if (b) x.expectStaticType<Exactly<int?>>();
+      break;
+    case 1:
+      b = true;
+      continue L;
+  }
+}
+
+switchLaterLabeled_toPromotedVar(int? x, int i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  switch (i) {
+    L:
+    case 0:
+      if (b) x.expectStaticType<Exactly<int?>>();
+      break;
+    case 1:
+      x = y;
+      continue L;
+  }
+}
+
+afterDo_toConditionalVar(int? x, int i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  do {
+    b = true;
+  } while (i-- > 0);
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterDo_toPromotedVar(int? x, int i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  do {
+    x = y;
+  } while (i-- > 0);
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterFor_toConditionalVar(int? x, int i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  for (int j = 0; j < i; j++) {
+    b = true;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterFor_toPromotedVar(int? x, int i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  for (int j = 0; j < i; j++) {
+    x = y;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterForEach_toConditionalVar(int? x, Iterable i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  for (var v in i) {
+    b = true;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterForEach_toPromotedVar(int? x, Iterable i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  for (var v in i) {
+    x = y;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterWhile_toConditionalVar(int? x, int i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  while (i-- > 0) {
+    b = true;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterWhile_toPromotedVar(int? x, int i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  while (i-- > 0) {
+    x = y;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterSwitch_toConditionalVar(int? x, int i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  switch (i) {
+    case 0:
+      b = true;
+      break;
+    case 1:
+      break;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterSwitch_toPromotedVar(int? x, int i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  switch (i) {
+    case 0:
+      x = y;
+      break;
+    case 1:
+      break;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+tryCatchCatch_toConditionalVar(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    b = true;
+  } catch (_) {
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+}
+
+tryCatchCatch_toPromotedVar(int? x, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    x = y;
+  } catch (_) {
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+}
+
+afterTryCatchTry_toConditionalVar(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    b = true;
+  } catch (_) {}
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryCatchTry_toPromotedVar(int? x, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    x = y;
+  } catch (_) {}
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryCatchCatch_toConditionalVar(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {} catch (_) {
+    b = true;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryCatchCatch_toPromotedVar(int? x, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {} catch (_) {
+    x = y;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+tryFinallyFinally_toConditionalVar(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    b = true;
+  } finally {
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+}
+
+tryFinallyFinally_toPromotedVar(int? x, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    x = y;
+  } finally {
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+}
+
+afterTryFinallyTry_toConditionalVar(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    b = true;
+  } finally {}
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryFinallyTry_toPromotedVar(int? x, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    x = y;
+  } finally {}
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryFinallyFinally_toConditionalVar(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {} finally {
+    b = true;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryFinallyFinally_toPromotedVar(int? x, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {} finally {
+    x = y;
+  }
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+main() {
+  direct_toConditionVar(0);
+  direct_toConditionVar(null);
+  direct_toPromotedVar(0, null);
+  direct_toPromotedVar(null, null);
+  lateInitializer_toConditionalVar(0);
+  lateInitializer_toConditionalVar(null);
+  lateInitializer_toPromotedVar(0, null);
+  lateInitializer_toPromotedVar(null, null);
+  afterConditionalThen_toConditionVar(0, true);
+  afterConditionalThen_toConditionVar(null, true);
+  afterConditionalThen_toPromotedVar(0, true, null);
+  afterConditionalThen_toPromotedVar(null, true, null);
+  afterConditionalElse_toConditionVar(0, false);
+  afterConditionalElse_toConditionVar(null, false);
+  afterConditionalElse_toPromotedVar(0, false, null);
+  afterConditionalElse_toPromotedVar(null, false, null);
+  afterIfStatementThen_toConditionVar(0, true);
+  afterIfStatementThen_toConditionVar(null, true);
+  afterIfStatementThen_toPromotedVar(0, true, null);
+  afterIfStatementThen_toPromotedVar(null, true, null);
+  afterIfStatementElse_toConditionVar(0, false);
+  afterIfStatementElse_toConditionVar(null, false);
+  afterIfStatementElse_toPromotedVar(0, false, null);
+  afterIfStatementElse_toPromotedVar(null, false, null);
+  afterIfListThen_toConditionVar(0, true);
+  afterIfListThen_toConditionVar(null, true);
+  afterIfListThen_toPromotedVar(0, true, null);
+  afterIfListThen_toPromotedVar(null, true, null);
+  afterIfListElse_toConditionVar(0, false);
+  afterIfListElse_toConditionVar(null, false);
+  afterIfListElse_toPromotedVar(0, false, null);
+  afterIfListElse_toPromotedVar(null, false, null);
+  afterIfSetThen_toConditionVar(0, true);
+  afterIfSetThen_toConditionVar(null, true);
+  afterIfSetThen_toPromotedVar(0, true, null);
+  afterIfSetThen_toPromotedVar(null, true, null);
+  afterIfSetElse_toConditionVar(0, false);
+  afterIfSetElse_toConditionVar(null, false);
+  afterIfSetElse_toPromotedVar(0, false, null);
+  afterIfSetElse_toPromotedVar(null, false, null);
+  afterIfMapKeyThen_toConditionVar(0, true);
+  afterIfMapKeyThen_toConditionVar(null, true);
+  afterIfMapKeyThen_toPromotedVar(0, true, null);
+  afterIfMapKeyThen_toPromotedVar(null, true, null);
+  afterIfMapKeyElse_toConditionVar(0, false);
+  afterIfMapKeyElse_toConditionVar(null, false);
+  afterIfMapKeyElse_toPromotedVar(0, false, null);
+  afterIfMapKeyElse_toPromotedVar(null, false, null);
+  afterIfMapValueThen_toConditionVar(0, true);
+  afterIfMapValueThen_toConditionVar(null, true);
+  afterIfMapValueThen_toPromotedVar(0, true, null);
+  afterIfMapValueThen_toPromotedVar(null, true, null);
+  afterIfMapValueElse_toConditionVar(0, false);
+  afterIfMapValueElse_toConditionVar(null, false);
+  afterIfMapValueElse_toPromotedVar(0, false, null);
+  afterIfMapValueElse_toPromotedVar(null, false, null);
+  doLater_toConditionalVar(0, 1);
+  doLater_toConditionalVar(null, 1);
+  doLater_toPromotedVar(0, 1, null);
+  doLater_toPromotedVar(null, 1, null);
+  forLater_toConditionalVar(0, 1);
+  forLater_toConditionalVar(null, 1);
+  forLater_toPromotedVar(0, 1, null);
+  forLater_toPromotedVar(null, 1, null);
+  forEachLater_toConditionalVar(0);
+  forEachLater_toConditionalVar(null);
+  forEachLater_toPromotedVar(0, null);
+  forEachLater_toPromotedVar(null, null);
+  whileLater_toConditionalVar(0, 1);
+  whileLater_toConditionalVar(null, 1);
+  whileLater_toPromotedVar(0, 1, null);
+  whileLater_toPromotedVar(null, 1, null);
+  switchLaterLabeled_toConditionalVar(0, 1);
+  switchLaterLabeled_toConditionalVar(null, 1);
+  switchLaterLabeled_toPromotedVar(0, 1, null);
+  switchLaterLabeled_toPromotedVar(null, 1, null);
+  afterDo_toConditionalVar(0, 1);
+  afterDo_toConditionalVar(null, 1);
+  afterDo_toPromotedVar(0, 1, null);
+  afterDo_toPromotedVar(null, 1, null);
+  afterFor_toConditionalVar(0, 1);
+  afterFor_toConditionalVar(null, 1);
+  afterFor_toPromotedVar(0, 1, null);
+  afterFor_toPromotedVar(null, 1, null);
+  afterForEach_toConditionalVar(0, [null]);
+  afterForEach_toConditionalVar(null, [null]);
+  afterForEach_toPromotedVar(0, [null], null);
+  afterForEach_toPromotedVar(null, [null], null);
+  afterWhile_toConditionalVar(0, 1);
+  afterWhile_toConditionalVar(null, 1);
+  afterWhile_toPromotedVar(0, 1, null);
+  afterWhile_toPromotedVar(null, 1, null);
+  afterSwitch_toConditionalVar(0, 0);
+  afterSwitch_toConditionalVar(null, 0);
+  afterSwitch_toPromotedVar(0, 0, null);
+  afterSwitch_toPromotedVar(null, 0, null);
+  tryCatchCatch_toConditionalVar(0);
+  tryCatchCatch_toConditionalVar(null);
+  tryCatchCatch_toPromotedVar(0, null);
+  tryCatchCatch_toPromotedVar(null, null);
+  afterTryCatchTry_toConditionalVar(0);
+  afterTryCatchTry_toConditionalVar(null);
+  afterTryCatchTry_toPromotedVar(0, null);
+  afterTryCatchTry_toPromotedVar(null, null);
+  afterTryCatchCatch_toConditionalVar(0);
+  afterTryCatchCatch_toConditionalVar(null);
+  afterTryCatchCatch_toPromotedVar(0, null);
+  afterTryCatchCatch_toPromotedVar(null, null);
+  tryFinallyFinally_toConditionalVar(0);
+  tryFinallyFinally_toConditionalVar(null);
+  tryFinallyFinally_toPromotedVar(0, null);
+  tryFinallyFinally_toPromotedVar(null, null);
+  afterTryFinallyTry_toConditionalVar(0);
+  afterTryFinallyTry_toConditionalVar(null);
+  afterTryFinallyTry_toPromotedVar(0, null);
+  afterTryFinallyTry_toPromotedVar(null, null);
+  afterTryFinallyFinally_toConditionalVar(0);
+  afterTryFinallyFinally_toConditionalVar(null);
+  afterTryFinallyFinally_toPromotedVar(0, null);
+  afterTryFinallyFinally_toPromotedVar(null, null);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_capture_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_capture_test.dart
new file mode 100644
index 0000000..b46d8c9
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_capture_test.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks various scenarios in which the use of a local variable for
+// type promotion is defeated by write capture of either the local variable
+// itself or the variable that would be promoted.
+
+capture_conditionVar_prior_to_assignment(int? x) {
+  bool b;
+  (bool b2) => b = b2;
+  b = x != null;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+capture_conditionVar_prior_to_assignment_from_other_condition(int? x) {
+  bool b1 = x != null;
+  bool b3;
+  (bool b2) => b3 = b2;
+  b3 = b1;
+  if (b3) x.expectStaticType<Exactly<int?>>();
+}
+
+capture_promotedVar_prior_to_assignment(int? x) {
+  int? y;
+  (int? z) => y = z;
+  y = x;
+  bool b = y != null;
+  if (b) y.expectStaticType<Exactly<int?>>();
+}
+
+capture_conditionVar_after_assignment(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  (bool b2) => b = b2;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+capture_conditionVar_after_assignment_from_other_condition(int? x) {
+  bool b1 = x != null;
+  bool b3 = b1;
+  if (b3) x.expectStaticType<Exactly<int>>();
+  (bool b2) => b3 = b2;
+  if (b3) x.expectStaticType<Exactly<int?>>();
+}
+
+capture_conditionVar_after_assignment_then_copy_to_other_condition(int? x) {
+  bool b1 = x != null;
+  bool b3;
+  (bool b2) => b1 = b2;
+  b3 = b1;
+  if (b3) x.expectStaticType<Exactly<int?>>();
+}
+
+capture_promotedVar_after_assignment(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  (int? y) => x = y;
+  if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+main() {
+  capture_conditionVar_prior_to_assignment(null);
+  capture_conditionVar_prior_to_assignment(0);
+  capture_conditionVar_prior_to_assignment_from_other_condition(null);
+  capture_conditionVar_prior_to_assignment_from_other_condition(0);
+  capture_promotedVar_prior_to_assignment(null);
+  capture_promotedVar_prior_to_assignment(0);
+  capture_conditionVar_after_assignment(null);
+  capture_conditionVar_after_assignment(0);
+  capture_conditionVar_after_assignment_from_other_condition(null);
+  capture_conditionVar_after_assignment_from_other_condition(0);
+  capture_conditionVar_after_assignment_then_copy_to_other_condition(null);
+  capture_conditionVar_after_assignment_then_copy_to_other_condition(0);
+  capture_promotedVar_after_assignment(null);
+  capture_promotedVar_after_assignment(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_does_not_detect_aliases_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_does_not_detect_aliases_test.dart
new file mode 100644
index 0000000..8449b67
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_does_not_detect_aliases_test.dart
@@ -0,0 +1,106 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks that type promotion via local variables does not promote
+// based on knowledge that two potentially promoted variables are "aliases" of
+// each other (both are known to contain the same value).
+//
+// Note, however, that if one condition variable is assigned to another, the
+// promotions *do* carry over; this is a side effect of "promote via local
+// booleans" mechanism and doesn't rely on detecting aliasing.
+//
+// We test both the situation where the variables have the same value due to
+// initialization as well as assignment.  We test both final and non-final
+// variables.
+
+promotedVar(int? x) {
+  {
+    int? y = x;
+    bool b = x != null;
+    if (b) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    final int? y = x;
+    bool b = x != null;
+    if (b) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    int? y;
+    y = x;
+    bool b = x != null;
+    if (b) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    final int? y;
+    y = x;
+    bool b = x != null;
+    if (b) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+}
+
+conditionalVar(int? x) {
+  {
+    bool b1 = x != null;
+    bool b2 = b1;
+    if (b1) {
+      x.expectStaticType<Exactly<int>>();
+    }
+    if (b2) {
+      x.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x != null;
+    final bool b2 = b1;
+    if (b1) {
+      x.expectStaticType<Exactly<int>>();
+    }
+    if (b2) {
+      x.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x != null;
+    bool b2;
+    b2 = b1;
+    if (b1) {
+      x.expectStaticType<Exactly<int>>();
+    }
+    if (b2) {
+      x.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x != null;
+    final bool b2;
+    b2 = b1;
+    if (b1) {
+      x.expectStaticType<Exactly<int>>();
+    }
+    if (b2) {
+      x.expectStaticType<Exactly<int>>();
+    }
+  }
+}
+
+main() {
+  promotedVar(0);
+  promotedVar(null);
+  conditionalVar(0);
+  conditionalVar(null);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_expression_types_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_expression_types_test.dart
new file mode 100644
index 0000000..5f37e8e
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_expression_types_test.dart
@@ -0,0 +1,774 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks whether a local boolean variable can be used to perform type
+// promotion, for various kinds of boolean expressions that we expect to cause
+// promotions, and various contexts in which those boolean variables could be
+// used.
+//
+// For the boolean variable, we test the forms:
+// - `<variable> is <Type>`
+// - `<variable> is! <Type>`
+// - `!<expr>`
+// - `<variable> == null`
+// - `<variable> != null`
+// - `null == <variable>`
+// - `null != <variable>`
+// - `<expr> && <expr>`
+// - `<expr> || <expr>`
+// - `<variable> is <Type> ? true : false`
+// - `<variable> = <expr>`
+// For the use site, we test the forms:
+// - `(<variable>)`
+// - `!<variable>`
+// - `<variable> && <expr>`
+// - `<expr> && <variable>`
+// - `<variable> || <expr>`
+// - `<expr> || <variable>`
+// - `<variable> ? <expr> : <expr>`
+// - `if (<variable>) ...`
+// - `while (<variable>) ...`
+// - `do ... while (<variable>)`
+// - `for (...; <variable>; ...) ...`
+
+bool _alwaysTrue(Object? x) => true;
+
+bool _alwaysFalse(Object? x) => false;
+
+is_(Object x) {
+  bool b = x is int;
+  if ((b)) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (!b) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (b && _alwaysTrue(x.expectStaticType<Exactly<int>>())) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysTrue(x.expectStaticType<Exactly<Object>>()) && b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b || _alwaysFalse(x.expectStaticType<Exactly<Object>>())) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysFalse(x.expectStaticType<Exactly<Object>>()) || b) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  while (b) {
+    x.expectStaticType<Exactly<int>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<Object>>();
+  do {
+    x.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  } while (b);
+  x.expectStaticType<Exactly<Object>>();
+  for (x.expectStaticType<Exactly<Object>>();
+      b;
+      x.expectStaticType<Exactly<int>>()) {
+    x.expectStaticType<Exactly<int>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+isNot(Object x) {
+  bool b = x is! int;
+  if ((b)) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (!b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b && _alwaysTrue(x.expectStaticType<Exactly<Object>>())) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysTrue(x.expectStaticType<Exactly<Object>>()) && b) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b || _alwaysFalse(x.expectStaticType<Exactly<int>>())) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (_alwaysFalse(x.expectStaticType<Exactly<Object>>()) || b) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (b) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  while (b) {
+    x.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<Object>>();
+  if (_alwaysFalse(null)) {
+    // We test this at compile time only because we don't want to have an
+    // infinite loop
+    do {
+      x.expectStaticType<Exactly<Object>>();
+    } while (b);
+    x.expectStaticType<Exactly<int>>();
+  }
+  x.expectStaticType<Exactly<Object>>();
+  for (x.expectStaticType<Exactly<Object>>();
+      b;
+      x.expectStaticType<Exactly<Object>>()) {
+    x.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+not(Object x) {
+  bool b = !(x is int);
+  if ((b)) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (!b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b && _alwaysTrue(x.expectStaticType<Exactly<Object>>())) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysTrue(x.expectStaticType<Exactly<Object>>()) && b) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b || _alwaysFalse(x.expectStaticType<Exactly<int>>())) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (_alwaysFalse(x.expectStaticType<Exactly<Object>>()) || b) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (b) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  while (b) {
+    x.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<Object>>();
+  if (_alwaysFalse(null)) {
+    // We test this at compile time only because we don't want to have an
+    // infinite loop
+    do {
+      x.expectStaticType<Exactly<Object>>();
+    } while (b);
+    x.expectStaticType<Exactly<int>>();
+  }
+  x.expectStaticType<Exactly<Object>>();
+  for (x.expectStaticType<Exactly<Object>>();
+      b;
+      x.expectStaticType<Exactly<Object>>()) {
+    x.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+eqNull(int? x) {
+  bool b = (x == null);
+  if ((b)) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (!b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (b && _alwaysTrue(x.expectStaticType<Exactly<int?>>())) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (_alwaysTrue(x.expectStaticType<Exactly<int?>>()) && b) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (b || _alwaysFalse(x.expectStaticType<Exactly<int>>())) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (_alwaysFalse(x.expectStaticType<Exactly<int?>>()) || b) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (b) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  while (b) {
+    x.expectStaticType<Exactly<int?>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<int?>>();
+  if (_alwaysFalse(null)) {
+    // We test this at compile time only because we don't want to have an
+    // infinite loop
+    do {
+      x.expectStaticType<Exactly<int?>>();
+    } while (b);
+    x.expectStaticType<Exactly<int>>();
+  }
+  x.expectStaticType<Exactly<int?>>();
+  for (x.expectStaticType<Exactly<int?>>();
+      b;
+      x.expectStaticType<Exactly<int?>>()) {
+    x.expectStaticType<Exactly<int?>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+notEqNull(int? x) {
+  bool b = x != null;
+  if ((b)) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (!b) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (b && _alwaysTrue(x.expectStaticType<Exactly<int>>())) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (_alwaysTrue(x.expectStaticType<Exactly<int?>>()) && b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (b || _alwaysFalse(x.expectStaticType<Exactly<int?>>())) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (_alwaysFalse(x.expectStaticType<Exactly<int?>>()) || b) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  while (b) {
+    x.expectStaticType<Exactly<int>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<int?>>();
+  do {
+    x.expectStaticType<Exactly<int?>>();
+    if (_alwaysTrue(null)) break;
+  } while (b);
+  x.expectStaticType<Exactly<int?>>();
+  for (x.expectStaticType<Exactly<int?>>();
+      b;
+      x.expectStaticType<Exactly<int>>()) {
+    x.expectStaticType<Exactly<int>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+nullEq(int? x) {
+  bool b = (null == x);
+  if ((b)) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (!b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (b && _alwaysTrue(x.expectStaticType<Exactly<int?>>())) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (_alwaysTrue(x.expectStaticType<Exactly<int?>>()) && b) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (b || _alwaysFalse(x.expectStaticType<Exactly<int>>())) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (_alwaysFalse(x.expectStaticType<Exactly<int?>>()) || b) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (b) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  while (b) {
+    x.expectStaticType<Exactly<int?>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<int?>>();
+  if (_alwaysFalse(null)) {
+    // We test this at compile time only because we don't want to have an
+    // infinite loop
+    do {
+      x.expectStaticType<Exactly<int?>>();
+    } while (b);
+    x.expectStaticType<Exactly<int>>();
+  }
+  x.expectStaticType<Exactly<int?>>();
+  for (x.expectStaticType<Exactly<int?>>();
+      b;
+      x.expectStaticType<Exactly<int?>>()) {
+    x.expectStaticType<Exactly<int?>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+nullNotEq(int? x) {
+  bool b = null != x;
+  if ((b)) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (!b) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (b && _alwaysTrue(x.expectStaticType<Exactly<int>>())) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (_alwaysTrue(x.expectStaticType<Exactly<int?>>()) && b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (b || _alwaysFalse(x.expectStaticType<Exactly<int?>>())) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (_alwaysFalse(x.expectStaticType<Exactly<int?>>()) || b) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  if (b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+  while (b) {
+    x.expectStaticType<Exactly<int>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<int?>>();
+  do {
+    x.expectStaticType<Exactly<int?>>();
+    if (_alwaysTrue(null)) break;
+  } while (b);
+  x.expectStaticType<Exactly<int?>>();
+  for (x.expectStaticType<Exactly<int?>>();
+      b;
+      x.expectStaticType<Exactly<int>>()) {
+    x.expectStaticType<Exactly<int>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+and(Object x, Object y) {
+  bool b = x is int && y is int;
+  if ((b)) {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  }
+  if (!b) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  }
+  if (b &&
+      _alwaysTrue([
+        x.expectStaticType<Exactly<int>>(),
+        y.expectStaticType<Exactly<int>>()
+      ])) {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysTrue([
+        x.expectStaticType<Exactly<Object>>(),
+        y.expectStaticType<Exactly<Object>>()
+      ]) &&
+      b) {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  }
+  if (b ||
+      _alwaysFalse([
+        x.expectStaticType<Exactly<Object>>(),
+        y.expectStaticType<Exactly<Object>>()
+      ])) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysFalse([
+        x.expectStaticType<Exactly<Object>>(),
+        y.expectStaticType<Exactly<Object>>()
+      ]) ||
+      b) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  }
+  if (b) {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  }
+  while (b) {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<Object>>();
+  y.expectStaticType<Exactly<Object>>();
+  do {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  } while (b);
+  x.expectStaticType<Exactly<Object>>();
+  y.expectStaticType<Exactly<Object>>();
+  for ([
+    x.expectStaticType<Exactly<Object>>(),
+    y.expectStaticType<Exactly<Object>>()
+  ];
+      b;
+      x.expectStaticType<Exactly<int>>(), y.expectStaticType<Exactly<int>>()) {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+or(Object x, Object y) {
+  bool b = x is! int || y is! int;
+  if ((b)) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  }
+  if (!b) {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  }
+  if (b &&
+      _alwaysTrue([
+        x.expectStaticType<Exactly<Object>>(),
+        y.expectStaticType<Exactly<Object>>()
+      ])) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysTrue([
+        x.expectStaticType<Exactly<Object>>(),
+        y.expectStaticType<Exactly<Object>>()
+      ]) &&
+      b) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  }
+  if (b ||
+      _alwaysFalse([
+        x.expectStaticType<Exactly<int>>(),
+        y.expectStaticType<Exactly<int>>()
+      ])) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  }
+  if (_alwaysFalse([
+        x.expectStaticType<Exactly<Object>>(),
+        y.expectStaticType<Exactly<Object>>()
+      ]) ||
+      b) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  }
+  if (b) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  }
+  while (b) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<Object>>();
+  y.expectStaticType<Exactly<Object>>();
+  if (_alwaysFalse(null)) {
+    // We test this at compile time only because we don't want to have an
+    // infinite loop
+    do {
+      x.expectStaticType<Exactly<Object>>();
+      y.expectStaticType<Exactly<Object>>();
+    } while (b);
+    x.expectStaticType<Exactly<int>>();
+    y.expectStaticType<Exactly<int>>();
+  }
+  x.expectStaticType<Exactly<Object>>();
+  y.expectStaticType<Exactly<Object>>();
+  for ([
+    x.expectStaticType<Exactly<Object>>(),
+    y.expectStaticType<Exactly<Object>>()
+  ];
+      b;
+      x.expectStaticType<Exactly<Object>>(),
+      y.expectStaticType<Exactly<Object>>()) {
+    x.expectStaticType<Exactly<Object>>();
+    y.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+conditional(Object x) {
+  bool b = x is int ? true : false;
+  if ((b)) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (!b) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  if (b && _alwaysTrue(x.expectStaticType<Exactly<int>>())) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysTrue(x.expectStaticType<Exactly<Object>>()) && b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b || _alwaysFalse(x.expectStaticType<Exactly<Object>>())) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysFalse(x.expectStaticType<Exactly<Object>>()) || b) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b) {
+    x.expectStaticType<Exactly<int>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  while (b) {
+    x.expectStaticType<Exactly<int>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<Object>>();
+  do {
+    x.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  } while (b);
+  x.expectStaticType<Exactly<Object>>();
+  for (x.expectStaticType<Exactly<Object>>();
+      b;
+      x.expectStaticType<Exactly<int>>()) {
+    x.expectStaticType<Exactly<int>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+assignment(Object x) {
+  // Note: flow analysis currently doesn't understand that `x = y` has the same
+  // value as `y`, so no promotion happens in this test.
+  bool b1;
+  bool b2 = b1 = x is int;
+  if ((b2)) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (!b2) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b2 && _alwaysTrue(x.expectStaticType<Exactly<Object>>())) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysTrue(x.expectStaticType<Exactly<Object>>()) && b2) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b2 || _alwaysFalse(x.expectStaticType<Exactly<Object>>())) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (_alwaysFalse(x.expectStaticType<Exactly<Object>>()) || b2) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  if (b2) {
+    x.expectStaticType<Exactly<Object>>();
+  } else {
+    x.expectStaticType<Exactly<Object>>();
+  }
+  while (b2) {
+    x.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  }
+  x.expectStaticType<Exactly<Object>>();
+  do {
+    x.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  } while (b2);
+  x.expectStaticType<Exactly<Object>>();
+  for (x.expectStaticType<Exactly<Object>>();
+      b2;
+      x.expectStaticType<Exactly<Object>>()) {
+    x.expectStaticType<Exactly<Object>>();
+    if (_alwaysTrue(null)) break;
+  }
+}
+
+main() {
+  is_('foo');
+  is_(0);
+  isNot('foo');
+  isNot(0);
+  not('foo');
+  not(0);
+  eqNull(null);
+  eqNull(0);
+  notEqNull(null);
+  notEqNull(0);
+  nullEq(null);
+  nullEq(0);
+  nullNotEq(null);
+  nullNotEq(0);
+  and('foo', 'bar');
+  and('foo', 1);
+  and(0, 'bar');
+  and(0, 1);
+  or('foo', 'bar');
+  or('foo', 1);
+  or(0, 'bar');
+  or(0, 1);
+  conditional('foo');
+  conditional(0);
+  assignment('foo');
+  assignment(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_join_equivalent_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_join_equivalent_test.dart
new file mode 100644
index 0000000..4158001
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_join_equivalent_test.dart
@@ -0,0 +1,264 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test verifies that when control flow paths are joined, flow analysis
+// does not recognize and coalesce distinct but equivalent assignments of test
+// expressions to a boolean.  So for example, even though this promotes:
+//
+//   bool b;
+//   b = x != null;
+//   if (b) { /* x is promoted to non-nullable */ }
+//
+// This does not:
+//
+//   bool b;
+//   if (...) {
+//     b = x != null;
+//   } else {
+//     b = x != null;
+//   }
+//   if (b) { /* x is not promoted */ }
+//
+// We test all flow control constructs where a join might occur, including:
+// - At the end of an if/else construct or conditional expression
+// - At the end of a loop where the "break" control flow path joins the main
+//   control flow path
+// - At the point in a "do" or "for" loop where the "continue" control flow path
+//   joins the main control flow path
+// - Inside a loop where multiple "break" or "continue" paths are implicitly
+//   joined
+// - Inside a switch statement where multiple "break" paths are implicitly
+//   joined
+// - At the end of an exhaustive switch statement where the last case is
+//   implicitly joined to the "break" path
+// - After a "catch" where the main control flow path is resumed
+// - After a labeled statement where the "break" control flow path is joined to
+//   the main control flow path
+
+enum E { E1, E2 }
+
+bool _alwaysFalse(dynamic d) => false;
+
+dynamic _alwaysThrow(dynamic d) {
+  throw 'foo';
+}
+
+test(int? x, bool b1, E e) {
+  {
+    bool b2;
+    b1
+        ? [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+        : [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null];
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    if (b1) {
+      b2 = x != null;
+      if (b2) x.expectStaticType<Exactly<int>>();
+    } else {
+      b2 = x != null;
+      if (b2) x.expectStaticType<Exactly<int>>();
+    }
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    [
+      if (b1)
+        [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+      else
+        [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+    ];
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    ({
+      if (b1)
+        [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+      else
+        [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+    });
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    ({
+      if (b1)
+        [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]: null
+      else
+        [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]: null
+    });
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    ({
+      if (b1)
+        null: [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+      else
+        null: [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+    });
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    do {
+      if (b1) {
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        break;
+      }
+      b2 = x != null;
+      if (b2) x.expectStaticType<Exactly<int>>();
+    } while (false);
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2 = false;
+    for (int i = 0; i < 1; i++) {
+      if (b1) {
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        break;
+      }
+      b2 = x != null;
+      if (b2) x.expectStaticType<Exactly<int>>();
+    }
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2 = false;
+    int i = 0;
+    while (i < 1) {
+      if (b1) {
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        break;
+      }
+      b2 = x != null;
+      if (b2) x.expectStaticType<Exactly<int>>();
+      i++;
+    }
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    do {
+      if (b1) {
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        continue;
+      }
+      b2 = x != null;
+      if (b2) x.expectStaticType<Exactly<int>>();
+    } while (_alwaysFalse(b2 ? x.expectStaticType<Exactly<int?>>() : null));
+  }
+  {
+    try {
+      bool b2;
+      for (;; _alwaysThrow(b2 ? x.expectStaticType<Exactly<int?>>() : null)) {
+        if (b1) {
+          b2 = x != null;
+          if (b2) x.expectStaticType<Exactly<int>>();
+          continue;
+        }
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+      }
+    } catch (_) {}
+  }
+  {
+    bool b2;
+    while (true) {
+      if (b1) {
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        break;
+      } else {
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        break;
+      }
+    }
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    do {
+      if (b1) {
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        continue;
+      } else {
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        continue;
+      }
+    } while (_alwaysFalse(b2 ? x.expectStaticType<Exactly<int?>>() : null));
+  }
+  {
+    bool b2;
+    switch (e) {
+      case E.E1:
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        break;
+      case E.E2:
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        break;
+    }
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    switch (e) {
+      case E.E1:
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        break;
+      case E.E2:
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+    }
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    try {
+      if (b1) throw 'foo';
+      b2 = x != null;
+      if (b2) x.expectStaticType<Exactly<int>>();
+    } catch (_) {
+      b2 = x != null;
+      if (b2) x.expectStaticType<Exactly<int>>();
+    }
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    bool b2;
+    label:
+    {
+      if (b1) {
+        b2 = x != null;
+        if (b2) x.expectStaticType<Exactly<int>>();
+        break label;
+      }
+      b2 = x != null;
+      if (b2) x.expectStaticType<Exactly<int>>();
+    }
+    if (b2) x.expectStaticType<Exactly<int?>>();
+  }
+}
+
+main() {
+  test(null, false, E.E1);
+  test(null, true, E.E2);
+  test(1, false, E.E1);
+  test(1, true, E.E2);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_logical_op_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_logical_op_test.dart
new file mode 100644
index 0000000..07ffdac
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_logical_op_test.dart
@@ -0,0 +1,471 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks that local boolean variables can be used to perform type
+// promotion even when combined using logical operators.  It also verifies that
+// these type promotions are appropriately invalidated by reassignments.
+
+testAnd(int? x, int? y, int? z, bool b) {
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    if (b1 && b2) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    x = z;
+    bool b2 = y is int;
+    if (b1 && b2) {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    y = z;
+    bool b2 = y is int;
+    if (b1 && b2) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    b1 = b;
+    bool b2 = y is int;
+    if (b1 && b2) {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    x = z;
+    if (b1 && b2) {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    y = z;
+    if (b1 && b2) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    b1 = b;
+    if (b1 && b2) {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    b2 = b;
+    if (b1 && b2) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    bool b3 = b1 && b2;
+    if (b3) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    x = z;
+    bool b2 = y is int;
+    bool b3 = b1 && b2;
+    if (b3) {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    y = z;
+    bool b2 = y is int;
+    bool b3 = b1 && b2;
+    if (b3) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    b1 = b;
+    bool b2 = y is int;
+    bool b3 = b1 && b2;
+    if (b3) {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    x = z;
+    bool b3 = b1 && b2;
+    if (b3) {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    y = z;
+    bool b3 = b1 && b2;
+    if (b3) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    b1 = b;
+    bool b3 = b1 && b2;
+    if (b3) {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    b2 = b;
+    bool b3 = b1 && b2;
+    if (b3) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    bool b3 = b1 && b2;
+    x = z;
+    if (b3) {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    bool b3 = b1 && b2;
+    y = z;
+    if (b3) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    bool b3 = b1 && b2;
+    b1 = b;
+    if (b3) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    bool b3 = b1 && b2;
+    b2 = b;
+    if (b3) {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is int;
+    bool b2 = y is int;
+    bool b3 = b1 && b2;
+    b3 = b;
+    if (b3) {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+}
+
+testOr(int? x, int? y, int? z, bool b) {
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    if (b1 || b2) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    x = z;
+    bool b2 = y is! int;
+    if (b1 || b2) {
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    y = z;
+    bool b2 = y is! int;
+    if (b1 || b2) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    b1 = b;
+    bool b2 = y is! int;
+    if (b1 || b2) {
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    x = z;
+    if (b1 || b2) {
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    y = z;
+    if (b1 || b2) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    b1 = b;
+    if (b1 || b2) {
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    b2 = b;
+    if (b1 || b2) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    bool b3 = b1 || b2;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    x = z;
+    bool b2 = y is! int;
+    bool b3 = b1 || b2;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    y = z;
+    bool b2 = y is! int;
+    bool b3 = b1 || b2;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    b1 = b;
+    bool b2 = y is! int;
+    bool b3 = b1 || b2;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    x = z;
+    bool b3 = b1 || b2;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    y = z;
+    bool b3 = b1 || b2;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    b1 = b;
+    bool b3 = b1 || b2;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    b2 = b;
+    bool b3 = b1 || b2;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    bool b3 = b1 || b2;
+    x = z;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    bool b3 = b1 || b2;
+    y = z;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    bool b3 = b1 || b2;
+    b1 = b;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    bool b3 = b1 || b2;
+    b2 = b;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int>>();
+      y.expectStaticType<Exactly<int>>();
+    }
+  }
+  {
+    bool b1 = x is! int;
+    bool b2 = y is! int;
+    bool b3 = b1 || b2;
+    b3 = b;
+    if (b3) {
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+      y.expectStaticType<Exactly<int?>>();
+    }
+  }
+}
+
+main() {
+  testAnd(1, 2, 3, true);
+  testAnd(1, 2, 3, false);
+  testAnd(1, 2, null, true);
+  testAnd(1, 2, null, false);
+  testAnd(1, null, 3, true);
+  testAnd(1, null, 3, false);
+  testAnd(1, null, null, true);
+  testAnd(1, null, null, false);
+  testAnd(null, 2, 3, true);
+  testAnd(null, 2, 3, false);
+  testAnd(null, 2, null, true);
+  testAnd(null, 2, null, false);
+  testAnd(null, null, 3, true);
+  testAnd(null, null, 3, false);
+  testAnd(null, null, null, true);
+  testAnd(null, null, null, false);
+  testOr(1, 2, 3, true);
+  testOr(1, 2, 3, false);
+  testOr(1, 2, null, true);
+  testOr(1, 2, null, false);
+  testOr(1, null, 3, true);
+  testOr(1, null, 3, false);
+  testOr(1, null, null, true);
+  testOr(1, null, null, false);
+  testOr(null, 2, 3, true);
+  testOr(null, 2, 3, false);
+  testOr(null, 2, null, true);
+  testOr(null, 2, null, false);
+  testOr(null, null, 3, true);
+  testOr(null, null, 3, false);
+  testOr(null, null, null, true);
+  testOr(null, null, null, false);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_null_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_null_test.dart
new file mode 100644
index 0000000..d995051
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_null_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks that a local variable whose value is `null` cannot be used
+// in place of a literal `null` in flow analysis.
+
+test(int? x) {
+  if (x == null) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int>>();
+  }
+  int? y = null;
+  if (x == y) {
+    x.expectStaticType<Exactly<int?>>();
+  } else {
+    x.expectStaticType<Exactly<int?>>();
+  }
+}
+
+main() {
+  test(0);
+  test(null);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_promoted_on_assignment_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_promoted_on_assignment_test.dart
new file mode 100644
index 0000000..e291ff8
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_promoted_on_assignment_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks that local variables can be used to perform type promotion
+// even in the case where the assignment ot (or initialization of) the local
+// variable promotes it.
+
+test(int? x) {
+  {
+    bool? b = null; // Makes `bool` a type of interest for `b`
+    b = x != null; // Promotes `b` to `bool`
+    b.expectStaticType<Exactly<bool>>();
+    if (b) {
+      x.expectStaticType<Exactly<int>>();
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+    }
+  }
+  {
+    Object b = Object();
+    if (b is! bool) {
+      // Makes `bool` a type of interest for `b`
+      b = x != null; // Promotes `b` to `bool`
+      b.expectStaticType<Exactly<bool>>();
+      if (b) {
+        x.expectStaticType<Exactly<int>>();
+      } else {
+        x.expectStaticType<Exactly<int?>>();
+      }
+    }
+  }
+  {
+    bool? b = x != null; // Promotes `b` to `bool`
+    b.expectStaticType<Exactly<bool>>();
+    if (b) {
+      x.expectStaticType<Exactly<int>>();
+    } else {
+      x.expectStaticType<Exactly<int?>>();
+    }
+  }
+}
+
+main() {
+  test(null);
+  test(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_promoted_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_promoted_test.dart
new file mode 100644
index 0000000..681bcb7
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_promoted_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks that local variables can be used to perform type promotion
+// even in the case where the local variable is itself promoted.
+
+test(int? x) {
+  Object b = x != null;
+  if (b is bool && b) {
+    x.expectStaticType<Exactly<int>>();
+  }
+}
+
+main() {
+  test(null);
+  test(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_test.dart
new file mode 100644
index 0000000..0e8450d
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_test.dart
@@ -0,0 +1,814 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks whether a local boolean variable can be used to perform type
+// promotion, for various ways of declaring and assigning to it.
+//
+// For the boolean, we test all combinations of:
+// - type `bool`, `Object`, `Object?`, or `dynamic`
+// - late or non-late
+// - final or non-final
+// - assigned at initialization time or later
+// For the promoted variable, we test all combinations of:
+// - parameter, unmodified from its initial value
+// - parameter, assigned later
+// - local variable, assigned at initialization
+// - local variable, assigned later
+
+parameterUnmodified(int? x) {
+  {
+    late final bool b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final bool b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late bool b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late bool b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final bool b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late final Object b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object? b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object? b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object? b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object? b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final dynamic b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final dynamic b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late dynamic b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late dynamic b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final dynamic b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    dynamic b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+}
+
+parameterModifiedLater(int? x, int? y) {
+  x = y;
+  {
+    late final bool b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final bool b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late bool b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late bool b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final bool b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late final Object b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object? b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object? b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object? b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object? b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final dynamic b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final dynamic b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late dynamic b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late dynamic b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final dynamic b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    dynamic b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+}
+
+localVariableInitialized(int? y) {
+  int? x = y;
+  {
+    late final bool b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final bool b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late bool b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late bool b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final bool b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late final Object b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object? b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object? b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object? b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object? b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final dynamic b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final dynamic b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late dynamic b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late dynamic b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final dynamic b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    dynamic b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+}
+
+localVariableModifiedLater(int? y) {
+  int? x;
+  x = y;
+  {
+    late final bool b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final bool b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late bool b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late bool b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final bool b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late final Object b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object? b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object? b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object? b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    final Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object? b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    Object? b;
+    b = x != null;
+    // We don't currently recognize that `b as bool` has the same value as `b`,
+    // so we don't promote.  TODO(paulberry): should we?
+    if (b as bool) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final dynamic b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late final dynamic b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    late dynamic b = x != null;
+    // We don't promote based on the initializers of late locals because we
+    // don't know when they execute.
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  {
+    late dynamic b;
+    b = x != null;
+    // We do promote based on assignments to late locals because we do know when
+    // they execute.
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    final dynamic b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    dynamic b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    dynamic b;
+    b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+}
+
+main() {
+  parameterUnmodified(null);
+  parameterUnmodified(0);
+  parameterModifiedLater(null, null);
+  parameterModifiedLater(null, 0);
+  localVariableInitialized(null);
+  localVariableInitialized(0);
+  localVariableModifiedLater(null);
+  localVariableModifiedLater(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_try_finally_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_try_finally_test.dart
new file mode 100644
index 0000000..96a4fa1
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_try_finally_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks that a local boolean condition variable can be used for
+// promotion in various corner case scenarios involving try/finally statements.
+
+test(int? x, bool b2) {
+  {
+    bool b = b2;
+    try {
+      b = x != null;
+      if (b) x.expectStaticType<Exactly<int>>();
+    } finally {
+      if (b) x.expectStaticType<Exactly<int?>>();
+    }
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b;
+    try {
+      b = x != null;
+      if (b) x.expectStaticType<Exactly<int>>();
+    } finally {
+      // Note: we can't do `if (b)` here because `b` is not definitely assigned.
+    }
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b = b2;
+    try {
+      if (b) x.expectStaticType<Exactly<int?>>();
+    } finally {
+      b = x != null;
+      if (b) x.expectStaticType<Exactly<int>>();
+    }
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+  {
+    bool b;
+    try {
+      // Note: we can't do `if (b)` here because `b` is not definitely assigned.
+    } finally {
+      b = x != null;
+      if (b) x.expectStaticType<Exactly<int>>();
+    }
+    if (b) x.expectStaticType<Exactly<int>>();
+  }
+}
+
+main() {
+  test(null, false);
+  test(null, true);
+  test(0, false);
+  test(0, true);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_undefeated_by_assignment_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_undefeated_by_assignment_test.dart
new file mode 100644
index 0000000..2ee8380
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_undefeated_by_assignment_test.dart
@@ -0,0 +1,566 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../static_type_helper.dart';
+
+// This test checks various scenarios in which the use of a local variable for
+// type promotion is not defeated by an assignment to the local variable itself
+// or an assignment to the variable that would be promoted, due to the fact that
+// there is no control flow path from the assignment to the use.
+
+lateInitializer_noAssignments(int? x) {
+  bool b = x != null;
+  late final y = b ? x.expectStaticType<Exactly<int>>() : 3;
+}
+
+afterConditionalThen_toConditionalVar(int? x, bool b2) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b2
+        ? [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+        : null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterConditionalThen_toPromotedVar(int? x, bool b2, int? y) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b2
+        ? [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+        : null;
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterConditionalElse_toConditionalVar(int? x, bool b2) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b2
+        ? null
+        : [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo'];
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterConditionalElse_toPromotedVar(int? x, bool b2, int? y) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    b2
+        ? null
+        : [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo'];
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfStatementThen_toConditionalVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  if (b2) {
+    b = true;
+    if (b) x.expectStaticType<Exactly<int?>>();
+    return;
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterIfStatementThen_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  if (b2) {
+    x = y;
+    if (b) x.expectStaticType<Exactly<int?>>();
+    return;
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterIfStatementElse_toConditionalVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  if (b2) {
+  } else {
+    b = true;
+    if (b) x.expectStaticType<Exactly<int?>>();
+    return;
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterIfStatementElse_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  if (b2) {
+  } else {
+    x = y;
+    if (b) x.expectStaticType<Exactly<int?>>();
+    return;
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterIfListThen_toConditionalVar(int? x, bool b2) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    [
+      if (b2)
+        [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+    ];
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfListThen_toPromotedVar(int? x, bool b2, int? y) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    [
+      if (b2) [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+    ];
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfListElse_toConditionalVar(int? x, bool b2) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    [
+      if (b2)
+        null
+      else
+        [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+    ];
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfListElse_toPromotedVar(int? x, bool b2, int? y) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    [
+      if (b2)
+        null
+      else
+        [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+    ];
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfSetThen_toConditionalVar(int? x, bool b2) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfSetThen_toPromotedVar(int? x, bool b2, int? y) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2) [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfSetElse_toConditionalVar(int? x, bool b2) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        null
+      else
+        [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfSetElse_toPromotedVar(int? x, bool b2, int? y) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        null
+      else
+        [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfMapKeyThen_toConditionalVar(int? x, bool b2) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']:
+            null
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfMapKeyThen_toPromotedVar(int? x, bool b2, int? y) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']: null
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfMapKeyElse_toConditionalVar(int? x, bool b2) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        null: null
+      else
+        [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']:
+            null
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfMapKeyElse_toPromotedVar(int? x, bool b2, int? y) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        null: null
+      else
+        [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']: null
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfMapValueThen_toConditionalVar(int? x, bool b2) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        null: [
+          b = true,
+          if (b) x.expectStaticType<Exactly<int?>>(),
+          throw 'foo'
+        ]
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfMapValueThen_toPromotedVar(int? x, bool b2, int? y) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        null: [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfMapValueElse_toConditionalVar(int? x, bool b2) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        null: null
+      else
+        null: [
+          b = true,
+          if (b) x.expectStaticType<Exactly<int?>>(),
+          throw 'foo'
+        ]
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterIfMapValueElse_toPromotedVar(int? x, bool b2, int? y) {
+  try {
+    bool b = x != null;
+    if (b) x.expectStaticType<Exactly<int>>();
+    ({
+      if (b2)
+        null: null
+      else
+        null: [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+    });
+    if (b) x.expectStaticType<Exactly<int>>();
+  } on String {}
+}
+
+afterSwitch_toConditionalVar(int? x, int i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  switch (i) {
+    case 0:
+      b = true;
+      if (b) x.expectStaticType<Exactly<int?>>();
+      return;
+    case 1:
+      break;
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterSwitch_toPromotedVar(int? x, int i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  switch (i) {
+    case 0:
+      x = y;
+      if (b) x.expectStaticType<Exactly<int?>>();
+      return;
+    case 1:
+      break;
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryCatchTry_toConditionalVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    if (b2) {
+      b = true;
+      if (b) x.expectStaticType<Exactly<int?>>();
+      return;
+    }
+  } catch (_) {
+    if (b) x.expectStaticType<Exactly<int?>>();
+    return;
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryCatchTry_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    if (b2) {
+      x = y;
+      if (b) x.expectStaticType<Exactly<int?>>();
+      return;
+    }
+  } catch (_) {
+    if (b) x.expectStaticType<Exactly<int?>>();
+    return;
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryCatchCatch_toConditionalVar(int? x) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {} catch (_) {
+    b = true;
+    if (b) x.expectStaticType<Exactly<int?>>();
+    return;
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryCatchCatch_toPromotedVar(int? x, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {} catch (_) {
+    x = y;
+    if (b) x.expectStaticType<Exactly<int?>>();
+    return;
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryFinallyTry_toConditionalVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    if (b2) {
+      b = true;
+      if (b) x.expectStaticType<Exactly<int?>>();
+      return;
+    }
+  } finally {
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryFinallyTry_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {
+    if (b2) {
+      x = y;
+      if (b) x.expectStaticType<Exactly<int?>>();
+      return;
+    }
+  } finally {
+    if (b) x.expectStaticType<Exactly<int?>>();
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryFinallyFinally_toConditionalVar(int? x, bool b2) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {} finally {
+    if (b2) {
+      b = true;
+      if (b) x.expectStaticType<Exactly<int?>>();
+      return;
+    }
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryFinallyFinally_toPromotedVar(int? x, bool b2, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  try {} finally {
+    if (b2) {
+      x = y;
+      if (b) x.expectStaticType<Exactly<int?>>();
+      return;
+    }
+  }
+  if (b) x.expectStaticType<Exactly<int>>();
+}
+
+switchLaterUnlabeled_toConditionalVar(int? x, int i) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  switch (i) {
+    case 0:
+      // Promotion is preserved because the case clause is unlabeled, so there's
+      // no path from the assignment back to here.
+      if (b) x.expectStaticType<Exactly<int>>();
+      break;
+    case 1:
+      b = true;
+      break;
+  }
+}
+
+switchLaterUnlabeled_toPromotedVar(int? x, int i, int? y) {
+  bool b = x != null;
+  if (b) x.expectStaticType<Exactly<int>>();
+  switch (i) {
+    case 0:
+      // Promotion is preserved because the case clause is unlabeled, so there's
+      // no path from the assignment back to here.
+      if (b) x.expectStaticType<Exactly<int>>();
+      break;
+    case 1:
+      x = y;
+      break;
+  }
+}
+
+main() {
+  lateInitializer_noAssignments(0);
+  lateInitializer_noAssignments(null);
+  afterConditionalThen_toConditionalVar(0, true);
+  afterConditionalThen_toConditionalVar(null, true);
+  afterConditionalThen_toPromotedVar(0, true, null);
+  afterConditionalThen_toPromotedVar(null, true, null);
+  afterConditionalElse_toConditionalVar(0, false);
+  afterConditionalElse_toConditionalVar(null, false);
+  afterConditionalElse_toPromotedVar(0, false, null);
+  afterConditionalElse_toPromotedVar(null, false, null);
+  afterIfStatementThen_toConditionalVar(0, true);
+  afterIfStatementThen_toConditionalVar(null, true);
+  afterIfStatementThen_toPromotedVar(0, true, null);
+  afterIfStatementThen_toPromotedVar(null, true, null);
+  afterIfStatementElse_toConditionalVar(0, false);
+  afterIfStatementElse_toConditionalVar(null, false);
+  afterIfStatementElse_toPromotedVar(0, false, null);
+  afterIfStatementElse_toPromotedVar(null, false, null);
+  afterIfListThen_toConditionalVar(0, true);
+  afterIfListThen_toConditionalVar(null, true);
+  afterIfListThen_toPromotedVar(0, true, null);
+  afterIfListThen_toPromotedVar(null, true, null);
+  afterIfListElse_toConditionalVar(0, false);
+  afterIfListElse_toConditionalVar(null, false);
+  afterIfListElse_toPromotedVar(0, false, null);
+  afterIfListElse_toPromotedVar(null, false, null);
+  afterIfSetThen_toConditionalVar(0, true);
+  afterIfSetThen_toConditionalVar(null, true);
+  afterIfSetThen_toPromotedVar(0, true, null);
+  afterIfSetThen_toPromotedVar(null, true, null);
+  afterIfSetElse_toConditionalVar(0, false);
+  afterIfSetElse_toConditionalVar(null, false);
+  afterIfSetElse_toPromotedVar(0, false, null);
+  afterIfSetElse_toPromotedVar(null, false, null);
+  afterIfMapKeyThen_toConditionalVar(0, true);
+  afterIfMapKeyThen_toConditionalVar(null, true);
+  afterIfMapKeyThen_toPromotedVar(0, true, null);
+  afterIfMapKeyThen_toPromotedVar(null, true, null);
+  afterIfMapKeyElse_toConditionalVar(0, false);
+  afterIfMapKeyElse_toConditionalVar(null, false);
+  afterIfMapKeyElse_toPromotedVar(0, false, null);
+  afterIfMapKeyElse_toPromotedVar(null, false, null);
+  afterIfMapValueThen_toConditionalVar(0, true);
+  afterIfMapValueThen_toConditionalVar(null, true);
+  afterIfMapValueThen_toPromotedVar(0, true, null);
+  afterIfMapValueThen_toPromotedVar(null, true, null);
+  afterIfMapValueElse_toConditionalVar(0, false);
+  afterIfMapValueElse_toConditionalVar(null, false);
+  afterIfMapValueElse_toPromotedVar(0, false, null);
+  afterIfMapValueElse_toPromotedVar(null, false, null);
+  afterSwitch_toConditionalVar(0, 1);
+  afterSwitch_toConditionalVar(null, 1);
+  afterSwitch_toPromotedVar(0, 1, null);
+  afterSwitch_toPromotedVar(null, 1, null);
+  afterTryCatchTry_toConditionalVar(0, false);
+  afterTryCatchTry_toConditionalVar(null, false);
+  afterTryCatchTry_toPromotedVar(0, false, null);
+  afterTryCatchTry_toPromotedVar(null, false, null);
+  afterTryCatchCatch_toConditionalVar(0);
+  afterTryCatchCatch_toConditionalVar(null);
+  afterTryCatchCatch_toPromotedVar(0, null);
+  afterTryCatchCatch_toPromotedVar(null, null);
+  afterTryFinallyTry_toConditionalVar(0, false);
+  afterTryFinallyTry_toConditionalVar(null, false);
+  afterTryFinallyTry_toPromotedVar(0, false, null);
+  afterTryFinallyTry_toPromotedVar(null, false, null);
+  afterTryFinallyFinally_toConditionalVar(0, false);
+  afterTryFinallyFinally_toConditionalVar(null, false);
+  afterTryFinallyFinally_toPromotedVar(0, false, null);
+  afterTryFinallyFinally_toPromotedVar(null, false, null);
+  switchLaterUnlabeled_toConditionalVar(0, 0);
+  switchLaterUnlabeled_toConditionalVar(null, 0);
+  switchLaterUnlabeled_toPromotedVar(0, 0, null);
+  switchLaterUnlabeled_toPromotedVar(null, 0, null);
+}
diff --git a/tests/lib/js/native_as_js_classes_static_test/default_library_namespace_test.dart b/tests/lib/js/native_as_js_classes_static_test/default_library_namespace_test.dart
deleted file mode 100644
index d230129..0000000
--- a/tests/lib/js/native_as_js_classes_static_test/default_library_namespace_test.dart
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Test errors with a library with the default namespace.
-
-@JS()
-library default_library_namespace_test;
-
-import 'package:js/js.dart';
-
-// Test same class name as a native class.
-@JS()
-class HTMLDocument {}
-//    ^
-// [web] JS interop class 'HTMLDocument' conflicts with natively supported class 'HtmlDocument' in 'dart:html'.
-
-// Test same annotation name as a native class.
-@JS('HTMLDocument')
-class HtmlDocument {}
-//    ^
-// [web] JS interop class 'HtmlDocument' conflicts with natively supported class 'HtmlDocument' in 'dart:html'.
-
-// Test annotation name with 'self' and 'window' prefixes.
-@JS('self.Window')
-class WindowWithSelf {}
-//    ^
-// [web] JS interop class 'WindowWithSelf' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('window.Window')
-class WindowWithWindow {}
-//    ^
-// [web] JS interop class 'WindowWithWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('self.window.self.window.self.Window')
-class WindowWithMultipleSelfsAndWindows {}
-//    ^
-// [web] JS interop class 'WindowWithMultipleSelfsAndWindows' conflicts with natively supported class 'Window' in 'dart:html'.
-
-// Test annotation with native class name but with a prefix that isn't 'self' or
-// 'window'.
-@JS('foo.Window')
-class WindowWithDifferentPrefix {}
-
-// Test same class name as a native class with multiple annotation names.
-// dart:html.Window uses both "Window" and "DOMWindow".
-@JS()
-class DOMWindow {}
-//    ^
-// [web] JS interop class 'DOMWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-// Test same annotation name as a native class with multiple annotation names
-// dart:html.Window uses both "Window" and "DOMWindow".
-@JS('DOMWindow')
-class DomWindow {}
-//    ^
-// [web] JS interop class 'DomWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-// Test different annotation name but with same class name as a @Native class.
-@JS('Foo')
-class Window {}
-
-// Dart classes don't have to worry about conflicts.
-class Element {}
-
-// Anonymous classes don't have to worry about conflicts either.
-@JS()
-@anonymous
-class HTMLElement {}
-
-@JS('HTMLElement')
-@anonymous
-class HtmlElement {}
-
-void main() {}
diff --git a/tests/lib/js/native_as_js_classes_static_test/global_library_namespace_test.dart b/tests/lib/js/native_as_js_classes_static_test/global_library_namespace_test.dart
deleted file mode 100644
index fb55aa6..0000000
--- a/tests/lib/js/native_as_js_classes_static_test/global_library_namespace_test.dart
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Test errors with a library with a global namespace.
-
-@JS('window')
-library global_library_namespace_test;
-
-import 'package:js/js.dart';
-
-@JS()
-class HTMLDocument {}
-//    ^
-// [web] JS interop class 'HTMLDocument' conflicts with natively supported class 'HtmlDocument' in 'dart:html'.
-
-@JS('HTMLDocument')
-class HtmlDocument {}
-//    ^
-// [web] JS interop class 'HtmlDocument' conflicts with natively supported class 'HtmlDocument' in 'dart:html'.
-
-@JS('self.Window')
-class WindowWithSelf {}
-//    ^
-// [web] JS interop class 'WindowWithSelf' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('window.Window')
-class WindowWithWindow {}
-//    ^
-// [web] JS interop class 'WindowWithWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('self.window.self.window.self.Window')
-class WindowWithMultipleSelfsAndWindows {}
-//    ^
-// [web] JS interop class 'WindowWithMultipleSelfsAndWindows' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('foo.Window')
-class WindowWithDifferentPrefix {}
-
-@JS()
-class DOMWindow {}
-//    ^
-// [web] JS interop class 'DOMWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('DOMWindow')
-class DomWindow {}
-//    ^
-// [web] JS interop class 'DomWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('Foo')
-class Window {}
-
-class Element {}
-
-@JS()
-@anonymous
-class HTMLElement {}
-
-@JS('HTMLElement')
-@anonymous
-class HtmlElement {}
-
-void main() {}
diff --git a/tests/lib/js/native_as_js_classes_static_test/local_library_namespace_test.dart b/tests/lib/js/native_as_js_classes_static_test/local_library_namespace_test.dart
deleted file mode 100644
index e529bfa..0000000
--- a/tests/lib/js/native_as_js_classes_static_test/local_library_namespace_test.dart
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Test errors with a library with a non-default or non-global namespace.
-// Note that none of the following should be errors in this case.
-
-@JS('foo')
-library global_library_namespace_test;
-
-import 'package:js/js.dart';
-
-@JS()
-class HTMLDocument {}
-
-@JS('HTMLDocument')
-class HtmlDocument {}
-
-@JS('self.Window')
-class WindowWithSelf {}
-
-@JS('window.Window')
-class WindowWithWindow {}
-
-@JS('self.window.self.window.self.Window')
-class WindowWithMultipleSelfsAndWindows {}
-
-@JS('foo.Window')
-class WindowWithDifferentPrefix {}
-
-@JS()
-class DOMWindow {}
-
-@JS('DOMWindow')
-class DomWindow {}
-
-@JS('Foo')
-class Window {}
-
-class Element {}
-
-@JS()
-@anonymous
-class HTMLElement {}
-
-@JS('HTMLElement')
-@anonymous
-class HtmlElement {}
-
-void main() {}
diff --git a/tools/VERSION b/tools/VERSION
index 823332b..aca474e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 207
+PRERELEASE 208
 PRERELEASE_PATCH 0
\ No newline at end of file