Version 2.12.0-150.0.dev

Merge commit 'ab2645c9f4b863d364658e9f05cc27de42b0204d' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index aff0dd8..0ab3d98 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -18,7 +18,7 @@
       "name": "_fe_analyzer_shared",
       "rootUri": "../pkg/_fe_analyzer_shared",
       "packageUri": "lib/",
-      "languageVersion": "2.6"
+      "languageVersion": "2.12"
     },
     {
       "name": "_fe_analyzer_shared_assigned_variables",
@@ -680,7 +680,7 @@
       "name": "test_reflective_loader",
       "rootUri": "../third_party/pkg/test_reflective_loader",
       "packageUri": "lib/",
-      "languageVersion": "1.8"
+      "languageVersion": "2.12"
     },
     {
       "name": "test_runner",
diff --git a/DEPS b/DEPS
index 5f32e2f..37c7c81 100644
--- a/DEPS
+++ b/DEPS
@@ -156,7 +156,7 @@
   "test_descriptor_tag": "1.1.1",
   "test_process_tag": "1.0.3",
   "term_glyph_rev": "6a0f9b6fb645ba75e7a00a4e20072678327a0347",
-  "test_reflective_loader_tag": "0.1.9",
+  "test_reflective_loader_rev": "b76ae201ab9c6f3b90643958965e7cc215a38e9b",
   "test_rev": "e37a93bbeae23b215972d1659ac865d71287ff6a",
   "typed_data_tag": "f94fc57b8e8c0e4fe4ff6cfd8290b94af52d3719",
   "usage_tag": "16fbfd90c58f16e016a295a880bc722d2547d2c9",
@@ -440,7 +440,7 @@
       Var("dart_git") + "test_process.git" + "@" + Var("test_process_tag"),
   Var("dart_root") + "/third_party/pkg/test_reflective_loader":
       Var("dart_git") + "test_reflective_loader.git" +
-      "@" + Var("test_reflective_loader_tag"),
+      "@" + Var("test_reflective_loader_rev"),
   Var("dart_root") + "/third_party/pkg/typed_data":
       Var("dart_git") + "typed_data.git" + "@" + Var("typed_data_tag"),
   Var("dart_root") + "/third_party/pkg/usage":
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni
index 96a32d4..0d74966 100644
--- a/build/toolchain/gcc_toolchain.gni
+++ b/build/toolchain/gcc_toolchain.gni
@@ -204,13 +204,7 @@
         command += " && " + strip_command
       } else if (defined(invoker.llvm_objcopy)) {
         strip = invoker.llvm_objcopy
-        if (defined(invoker.llvm_objcopy_extra_args)) {
-          extra_args = invoker.llvm_objcopy_extra_args
-        } else {
-          extra_args = ""
-        }
-        strip_command =
-            "${strip} --strip-all ${extra_args} $outfile $stripped_outfile"
+        strip_command = "${strip} --strip-all $outfile $stripped_outfile"
         command += " && " + strip_command
       }
       if (defined(invoker.postlink)) {
diff --git a/build/toolchain/linux/BUILD.gn b/build/toolchain/linux/BUILD.gn
index 71038ed..4692784 100644
--- a/build/toolchain/linux/BUILD.gn
+++ b/build/toolchain/linux/BUILD.gn
@@ -52,17 +52,6 @@
   ld = cxx
   llvm_objcopy = "${prefix}/llvm-objcopy"
 
-  # When producing ARM builds we drop .ARM.exidx/extab sections. These sections
-  # don't contain any useful information (we don't use exceptions or
-  # unwind C++ frames and most of the dart binary is in fact not covered by
-  # them), however they have been seen to break dynamic linker in older glibc
-  # versions (pre 2.23) because .ARM.exidx ends up being positioned between
-  # .rel.dyn and .rel.plt sections while older versions of dynamic linker
-  # expect these two sections to appear one after another in the ELF file.
-  # See https://github.com/dart-lang/sdk/issues/41644.
-  llvm_objcopy_extra_args =
-      "--remove-section .ARM.exidx --remove-section .ARM.extab"
-
   toolchain_cpu = "arm"
   toolchain_os = "linux"
   is_clang = true
diff --git a/pkg/_fe_analyzer_shared/lib/src/base/errors.dart b/pkg/_fe_analyzer_shared/lib/src/base/errors.dart
index 2e138d8..46bc443 100644
--- a/pkg/_fe_analyzer_shared/lib/src/base/errors.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/base/errors.dart
@@ -2,8 +2,6 @@
 // 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';
-
 import 'customized_codes.dart';
 
 /// An error code associated with an [AnalysisError].
@@ -23,7 +21,7 @@
 
   final String _message;
 
-  final String _correction;
+  final String? _correction;
 
   /**
    * Return `true` if diagnostics with this code have documentation for them
@@ -43,25 +41,27 @@
    * given [correction] template.
    */
   const ErrorCode({
-    String correction,
+    String? correction,
     this.hasPublishedDocs = false,
     this.isUnresolvedIdentifier: false,
-    @required String message,
-    @required this.name,
-    @required this.uniqueName,
+    required String message,
+    required this.name,
+    required this.uniqueName,
   })  : _correction = correction,
         _message = message,
+        // ignore: unnecessary_null_comparison
         assert(hasPublishedDocs != null),
+        // ignore: unnecessary_null_comparison
         assert(isUnresolvedIdentifier != null);
 
   @Deprecated('Use the default constructor')
   const ErrorCode.temporary2({
-    String correction,
+    String? correction,
     bool hasPublishedDocs = false,
     bool isUnresolvedIdentifier = false,
-    @required String message,
-    @required String name,
-    @required String uniqueName,
+    required String message,
+    required String name,
+    required String uniqueName,
   }) : this(
           correction: correction,
           hasPublishedDocs: hasPublishedDocs,
@@ -76,7 +76,7 @@
    * or `null` if there is no correction information for this error. The
    * correction should indicate how the user can fix the error.
    */
-  String get correction => customizedCorrections[uniqueName] ?? _correction;
+  String? get correction => customizedCorrections[uniqueName] ?? _correction;
 
   /**
    * The severity of the error.
@@ -102,7 +102,7 @@
    * Return a URL that can be used to access documentation for diagnostics with
    * this code, or `null` if there is no published documentation.
    */
-  String get url {
+  String? get url {
     if (hasPublishedDocs) {
       return 'https://dart.dev/tools/diagnostic-messages#${name.toLowerCase()}';
     }
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 7610ce4..1a1df17 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
@@ -24,7 +24,7 @@
 /// We use the term "node" to refer generally to a loop statement, switch
 /// statement, try statement, loop collection element, local function, or
 /// closure.
-class AssignedVariables<Node, Variable> {
+class AssignedVariables<Node extends Object, Variable extends Object> {
   /// Mapping from a node to the info for that node.
   final Map<Node, AssignedVariablesNodeInfo<Variable>> _info =
       new Map<Node, AssignedVariablesNodeInfo<Variable>>.identity();
@@ -177,13 +177,13 @@
   // general elements in the front-end.
   void reassignInfo(Node from, Node to) {
     assert(!_info.containsKey(to), "Node $to already has info: ${_info[to]}");
-    AssignedVariablesNodeInfo<Variable> info = _info.remove(from);
+    AssignedVariablesNodeInfo<Variable>? info = _info.remove(from);
     assert(
         info != null,
         'No information for $from (${from.hashCode}) in '
         '{${_info.keys.map((k) => '$k (${k.hashCode})').join(',')}}');
 
-    _info[to] = info;
+    _info[to] = info!;
   }
 
   /// This method may be called at any time between a call to [deferNode] and
@@ -226,7 +226,7 @@
 /// Extension of [AssignedVariables] intended for use in tests.  This class
 /// exposes the results of the analysis so that they can be tested directly.
 /// Not intended to be used by clients of flow analysis.
-class AssignedVariablesForTesting<Node, Variable>
+class AssignedVariablesForTesting<Node extends Object, Variable extends Object>
     extends AssignedVariables<Node, Variable> {
   Set<Variable> get capturedAnywhere => _anywhere._captured;
 
@@ -252,7 +252,7 @@
 }
 
 /// Information tracked by [AssignedVariables] for a single node.
-class AssignedVariablesNodeInfo<Variable> {
+class AssignedVariablesNodeInfo<Variable extends Object> {
   /// The set of local variables that are potentially written in the node.
   final Set<Variable> _written = new Set<Variable>.identity();
 
@@ -270,7 +270,7 @@
 
 /// A collection of flow models representing the possible outcomes of evaluating
 /// an expression that are relevant to flow analysis.
-class ExpressionInfo<Variable, Type> {
+class ExpressionInfo<Variable extends Object, Type extends Object> {
   /// The state after the expression evaluates, if we don't care what it
   /// evaluates to.
   final FlowModel<Variable, Type> after;
@@ -289,8 +289,8 @@
 
   /// Compute a new [ExpressionInfo] based on this one, but with the roles of
   /// [ifTrue] and [ifFalse] reversed.
-  static ExpressionInfo<Variable, Type> invert<Variable, Type>(
-          ExpressionInfo<Variable, Type> info) =>
+  static ExpressionInfo<Variable, Type> invert<Variable extends Object,
+          Type extends Object>(ExpressionInfo<Variable, Type> info) =>
       new ExpressionInfo<Variable, Type>(info.after, info.ifFalse, info.ifTrue);
 }
 
@@ -300,8 +300,8 @@
 /// The client should create one instance of this class for every method, field,
 /// or top level variable to be analyzed, and call the appropriate methods
 /// while visiting the code for type inference.
-abstract class FlowAnalysis<Node, Statement extends Node, Expression, Variable,
-    Type> {
+abstract class FlowAnalysis<Node extends Object, Statement extends Node,
+    Expression extends Object, Variable extends Object, Type extends Object> {
   factory FlowAnalysis(TypeOperations<Variable, Type> typeOperations,
       AssignedVariables<Node, Variable> assignedVariables) {
     return new _FlowAnalysisImpl(typeOperations, assignedVariables);
@@ -414,7 +414,7 @@
   /// the loop condition should cause any promotions to occur.  If [condition]
   /// is null, the condition is understood to be empty (equivalent to a
   /// condition of `true`).
-  void for_bodyBegin(Statement node, Expression condition);
+  void for_bodyBegin(Statement? node, Expression? condition);
 
   /// Call this method just before visiting the condition of a conventional
   /// "for" statement or collection element.
@@ -461,7 +461,7 @@
   /// be the variable assigned to by the loop (if it is promotable, otherwise
   /// null).  [writtenType] should be the type written to that variable (i.e.
   /// if the loop iterates over `List<Foo>`, it should be `Foo`).
-  void forEach_bodyBegin(Node node, Variable loopVariable, Type writtenType);
+  void forEach_bodyBegin(Node node, Variable? loopVariable, Type writtenType);
 
   /// Call this method just before visiting the body of a "for-in" statement or
   /// collection element.  See [forEach_bodyBegin] for details.
@@ -573,7 +573,7 @@
 
   /// Call this method before visiting a labeled statement.
   /// Call [labeledStatement_end] after visiting the statement.
-  void labeledStatement_begin(Node node);
+  void labeledStatement_begin(Statement node);
 
   /// Call this method after visiting a labeled statement.
   void labeledStatement_end();
@@ -594,14 +594,14 @@
   /// [rightOperand] should be the RHS.  [isAnd] should indicate whether the
   /// logical operator is "&&" or "||".
   void logicalBinaryOp_end(Expression wholeExpression, Expression rightOperand,
-      {@required bool isAnd});
+      {required bool isAnd});
 
   /// Call this method after visiting the LHS of a logical binary operation
   /// ("||" or "&&").
   /// [rightOperand] should be the LHS.  [isAnd] should indicate whether the
   /// logical operator is "&&" or "||".
   void logicalBinaryOp_rightBegin(Expression leftOperand,
-      {@required bool isAnd});
+      {required bool isAnd});
 
   /// Call this method after visiting a logical not ("!") expression.
   /// [notExpression] should be the complete expression.  [operand] should be
@@ -630,7 +630,7 @@
   /// code being analyzed is `x?.y?.z(x)`, [nullAwareAccess_rightBegin] should
   /// be called once upon reaching each `?.`, but [nullAwareAccess_end] should
   /// not be called until after processing the method call to `z(x)`.
-  void nullAwareAccess_rightBegin(Expression target, Type targetType);
+  void nullAwareAccess_rightBegin(Expression? target, Type targetType);
 
   /// Call this method when encountering an expression that is a `null` literal.
   void nullLiteral(Expression expression);
@@ -649,7 +649,7 @@
 
   /// Retrieves the type that the [variable] is promoted to, if the [variable]
   /// is currently promoted.  Otherwise returns `null`.
-  Type promotedType(Variable variable);
+  Type? promotedType(Variable variable);
 
   /// Call this method just before visiting one of the cases in the body of a
   /// switch statement.  See [switchStatement_expressionEnd] for details.
@@ -723,7 +723,7 @@
   /// clause, or `null` if there is no exception variable.  Similar for
   /// [stackTraceVariable].
   void tryCatchStatement_catchBegin(
-      Variable exceptionVariable, Variable stackTraceVariable);
+      Variable? exceptionVariable, Variable? stackTraceVariable);
 
   /// Call this method just after visiting a catch clause of a "try/catch"
   /// statement.  See [tryCatchStatement_bodyBegin] for details.
@@ -768,7 +768,7 @@
   ///
   /// If the variable's type is currently promoted, the promoted type is
   /// returned.  Otherwise `null` is returned.
-  Type variableRead(Expression expression, Variable variable);
+  Type? variableRead(Expression expression, Variable variable);
 
   /// Call this method after visiting the condition part of a "while" statement.
   /// [whileStatement] should be the full while statement.  [condition] should
@@ -797,8 +797,9 @@
 
 /// Alternate implementation of [FlowAnalysis] that prints out inputs and output
 /// at the API boundary, for assistance in debugging.
-class FlowAnalysisDebug<Node, Statement extends Node, Expression, Variable,
-    Type> implements FlowAnalysis<Node, Statement, Expression, Variable, Type> {
+class FlowAnalysisDebug<Node extends Object, Statement extends Node,
+        Expression extends Object, Variable extends Object, Type extends Object>
+    implements FlowAnalysis<Node, Statement, Expression, Variable, Type> {
   _FlowAnalysisImpl<Node, Statement, Expression, Variable, Type> _wrapped;
 
   bool _exceptionOccurred = false;
@@ -921,7 +922,7 @@
   }
 
   @override
-  void for_bodyBegin(Statement node, Expression condition) {
+  void for_bodyBegin(Statement? node, Expression? condition) {
     _wrap('for_bodyBegin($node, $condition)',
         () => _wrapped.for_bodyBegin(node, condition));
   }
@@ -942,7 +943,7 @@
   }
 
   @override
-  void forEach_bodyBegin(Node node, Variable loopVariable, Type writtenType) {
+  void forEach_bodyBegin(Node node, Variable? loopVariable, Type writtenType) {
     return _wrap('forEach_bodyBegin($node, $loopVariable, $writtenType)',
         () => _wrapped.forEach_bodyBegin(node, loopVariable, writtenType));
   }
@@ -1045,7 +1046,7 @@
   }
 
   @override
-  void labeledStatement_begin(Node node) {
+  void labeledStatement_begin(Statement node) {
     return _wrap('labeledStatement_begin($node)',
         () => _wrapped.labeledStatement_begin(node));
   }
@@ -1074,7 +1075,7 @@
 
   @override
   void logicalBinaryOp_end(Expression wholeExpression, Expression rightOperand,
-      {@required bool isAnd}) {
+      {required bool isAnd}) {
     _wrap(
         'logicalBinaryOp_end($wholeExpression, $rightOperand, isAnd: $isAnd)',
         () => _wrapped.logicalBinaryOp_end(wholeExpression, rightOperand,
@@ -1083,7 +1084,7 @@
 
   @override
   void logicalBinaryOp_rightBegin(Expression leftOperand,
-      {@required bool isAnd}) {
+      {required bool isAnd}) {
     _wrap('logicalBinaryOp_rightBegin($leftOperand, isAnd: $isAnd)',
         () => _wrapped.logicalBinaryOp_rightBegin(leftOperand, isAnd: isAnd));
   }
@@ -1106,7 +1107,7 @@
   }
 
   @override
-  void nullAwareAccess_rightBegin(Expression target, Type targetType) {
+  void nullAwareAccess_rightBegin(Expression? target, Type targetType) {
     _wrap('nullAwareAccess_rightBegin($target, $targetType)',
         () => _wrapped.nullAwareAccess_rightBegin(target, targetType));
   }
@@ -1131,7 +1132,7 @@
   }
 
   @override
-  Type promotedType(Variable variable) {
+  Type? promotedType(Variable variable) {
     return _wrap(
         'promotedType($variable)', () => _wrapped.promotedType(variable),
         isQuery: true);
@@ -1169,7 +1170,7 @@
 
   @override
   void tryCatchStatement_catchBegin(
-      Variable exceptionVariable, Variable stackTraceVariable) {
+      Variable? exceptionVariable, Variable? stackTraceVariable) {
     return _wrap(
         'tryCatchStatement_catchBegin($exceptionVariable, $stackTraceVariable)',
         () => _wrapped.tryCatchStatement_catchBegin(
@@ -1207,7 +1208,7 @@
   }
 
   @override
-  Type variableRead(Expression expression, Variable variable) {
+  Type? variableRead(Expression expression, Variable variable) {
     return _wrap('variableRead($expression, $variable)',
         () => _wrapped.variableRead(expression, variable),
         isQuery: true, isPure: false);
@@ -1241,7 +1242,7 @@
   }
 
   T _wrap<T>(String description, T callback(),
-      {bool isQuery: false, bool isPure}) {
+      {bool isQuery: false, bool? isPure}) {
     isPure ??= isQuery;
     print(description);
     T result;
@@ -1270,7 +1271,7 @@
 /// Instances of this class are immutable, so the methods below that "update"
 /// the state actually leave `this` unchanged and return a new state object.
 @visibleForTesting
-class FlowModel<Variable, Type> {
+class FlowModel<Variable extends Object, Type extends Object> {
   final Reachability reachable;
 
   /// For each variable being tracked by flow analysis, the variable's model.
@@ -1300,9 +1301,11 @@
 
   @visibleForTesting
   FlowModel.withInfo(this.reachable, this.variableInfo) {
+    // ignore:unnecessary_null_comparison
     assert(reachable != null);
     assert(() {
       for (VariableModel<Variable, Type> value in variableInfo.values) {
+        // ignore:unnecessary_null_comparison
         assert(value != null);
       }
       return true;
@@ -1332,7 +1335,7 @@
   FlowModel<Variable, Type> conservativeJoin(
       Iterable<Variable> writtenVariables,
       Iterable<Variable> capturedVariables) {
-    Map<Variable, VariableModel<Variable, Type>> newVariableInfo;
+    Map<Variable, VariableModel<Variable, Type>>? newVariableInfo;
 
     for (Variable variable in writtenVariables) {
       VariableModel<Variable, Type> info = infoFor(variable);
@@ -1346,7 +1349,7 @@
     }
 
     for (Variable variable in capturedVariables) {
-      VariableModel<Variable, Type> info = variableInfo[variable];
+      VariableModel<Variable, Type>? info = variableInfo[variable];
       if (info == null) {
         (newVariableInfo ??=
             new Map<Variable, VariableModel<Variable, Type>>.from(
@@ -1400,7 +1403,7 @@
         in variableInfo.entries) {
       Variable variable = entry.key;
       VariableModel<Variable, Type> variableModel = entry.value;
-      VariableModel<Variable, Type> otherVariableModel =
+      VariableModel<Variable, Type>? otherVariableModel =
           otherVariableInfo[variable];
       VariableModel<Variable, Type> newVariableModel =
           otherVariableModel == null
@@ -1452,7 +1455,7 @@
         in variableInfo.entries) {
       Variable variable = entry.key;
       VariableModel<Variable, Type> thisModel = entry.value;
-      VariableModel<Variable, Type> otherModel = other.variableInfo[variable];
+      VariableModel<Variable, Type>? otherModel = other.variableInfo[variable];
       if (otherModel == null) {
         variableInfoMatchesThis = false;
         continue;
@@ -1512,7 +1515,7 @@
       return new ExpressionInfo<Variable, Type>(this, this, this);
     }
 
-    Type previousType = info.promotedTypes?.last;
+    Type? previousType = info.promotedTypes?.last;
     previousType ??= typeOperations.variableType(variable);
 
     Type newType = typeOperations.promoteToNonNull(previousType);
@@ -1547,10 +1550,10 @@
       return this;
     }
 
-    Type previousType = info.promotedTypes?.last;
+    Type? previousType = info.promotedTypes?.last;
     previousType ??= typeOperations.variableType(variable);
 
-    Type newType = typeOperations.tryPromoteToType(type, previousType);
+    Type? newType = typeOperations.tryPromoteToType(type, previousType);
     if (newType == null || typeOperations.isSameType(newType, previousType)) {
       return this;
     }
@@ -1578,11 +1581,11 @@
       return new ExpressionInfo<Variable, Type>(this, this, this);
     }
 
-    Type previousType = info.promotedTypes?.last;
+    Type? previousType = info.promotedTypes?.last;
     previousType ??= typeOperations.variableType(variable);
 
     FlowModel<Variable, Type> modelIfSuccessful = this;
-    Type typeIfSuccess = typeOperations.tryPromoteToType(type, previousType);
+    Type? typeIfSuccess = typeOperations.tryPromoteToType(type, previousType);
     if (typeIfSuccess != null &&
         !typeOperations.isSameType(typeIfSuccess, previousType)) {
       assert(typeOperations.isSubtypeOf(typeIfSuccess, previousType),
@@ -1592,7 +1595,7 @@
     }
 
     Type factoredType = typeOperations.factor(previousType, type);
-    Type typeIfFailed;
+    Type? typeIfFailed;
     if (typeOperations.isNever(factoredType)) {
       // Promoting to `Never` would mark the code as unreachable.  But it might
       // be reachable due to mixed mode unsoundness.  So don't promote.
@@ -1631,7 +1634,7 @@
   /// previous type promotion is removed.
   FlowModel<Variable, Type> write(Variable variable, Type writtenType,
       TypeOperations<Variable, Type> typeOperations) {
-    VariableModel<Variable, Type> infoForVar = variableInfo[variable];
+    VariableModel<Variable, Type>? infoForVar = variableInfo[variable];
     if (infoForVar == null) return this;
 
     VariableModel<Variable, Type> newInfoForVar =
@@ -1656,8 +1659,8 @@
     TypeOperations<Variable, Type> typeOperations,
     Variable variable,
     VariableModel<Variable, Type> info,
-    Type testedType,
-    Type promotedType,
+    Type? testedType,
+    Type? promotedType,
   ) {
     List<Type> newTested = info.tested;
     if (testedType != null) {
@@ -1665,7 +1668,7 @@
           info.tested, testedType, typeOperations);
     }
 
-    List<Type> newPromotedTypes = info.promotedTypes;
+    List<Type>? newPromotedTypes = info.promotedTypes;
     Reachability newReachable = reachable;
     if (promotedType != null) {
       newPromotedTypes =
@@ -1690,7 +1693,7 @@
   /// with [model].
   FlowModel<Variable, Type> _updateVariableInfo(
       Variable variable, VariableModel<Variable, Type> model,
-      {Reachability reachable}) {
+      {Reachability? reachable}) {
     reachable ??= this.reachable;
     Map<Variable, VariableModel<Variable, Type>> newVariableInfo =
         new Map<Variable, VariableModel<Variable, Type>>.from(variableInfo);
@@ -1707,13 +1710,14 @@
   /// are kept only if they are common to both input states; if a variable is
   /// promoted to one type in one state and a subtype in the other state, the
   /// less specific type promotion is kept.
-  static FlowModel<Variable, Type> join<Variable, Type>(
+  static FlowModel<Variable, Type>
+      join<Variable extends Object, Type extends Object>(
     TypeOperations<Variable, Type> typeOperations,
-    FlowModel<Variable, Type> first,
-    FlowModel<Variable, Type> second,
+    FlowModel<Variable, Type>? first,
+    FlowModel<Variable, Type>? second,
     Map<Variable, VariableModel<Variable, Type>> emptyVariableMap,
   ) {
-    if (first == null) return second;
+    if (first == null) return second!;
     if (second == null) return first;
 
     assert(identical(first.reachable.parent, second.reachable.parent));
@@ -1739,7 +1743,7 @@
   /// Joins two "variable info" maps.  See [join] for details.
   @visibleForTesting
   static Map<Variable, VariableModel<Variable, Type>>
-      joinVariableInfo<Variable, Type>(
+      joinVariableInfo<Variable extends Object, Type extends Object>(
     TypeOperations<Variable, Type> typeOperations,
     Map<Variable, VariableModel<Variable, Type>> first,
     Map<Variable, VariableModel<Variable, Type>> second,
@@ -1757,7 +1761,7 @@
     for (MapEntry<Variable, VariableModel<Variable, Type>> entry
         in first.entries) {
       Variable variable = entry.key;
-      VariableModel<Variable, Type> secondModel = second[variable];
+      VariableModel<Variable, Type>? secondModel = second[variable];
       if (secondModel == null) {
         alwaysFirst = false;
       } else {
@@ -1778,13 +1782,14 @@
 
   /// Models the result of joining the flow models [first] and [second] at the
   /// merge of two control flow paths.
-  static FlowModel<Variable, Type> merge<Variable, Type>(
+  static FlowModel<Variable, Type>
+      merge<Variable extends Object, Type extends Object>(
     TypeOperations<Variable, Type> typeOperations,
-    FlowModel<Variable, Type> first,
-    FlowModel<Variable, Type> second,
+    FlowModel<Variable, Type>? first,
+    FlowModel<Variable, Type>? second,
     Map<Variable, VariableModel<Variable, Type>> emptyVariableMap,
   ) {
-    if (first == null) return second.unsplit();
+    if (first == null) return second!.unsplit();
     if (second == null) return first.unsplit();
 
     assert(identical(first.reachable.parent, second.reachable.parent));
@@ -1809,11 +1814,12 @@
 
   /// Creates a new [FlowModel] object, unless it is equivalent to either
   /// [first] or [second], in which case one of those objects is re-used.
-  static FlowModel<Variable, Type> _identicalOrNew<Variable, Type>(
-      FlowModel<Variable, Type> first,
-      FlowModel<Variable, Type> second,
-      Reachability newReachable,
-      Map<Variable, VariableModel<Variable, Type>> newVariableInfo) {
+  static FlowModel<Variable, Type>
+      _identicalOrNew<Variable extends Object, Type extends Object>(
+          FlowModel<Variable, Type> first,
+          FlowModel<Variable, Type> second,
+          Reachability newReachable,
+          Map<Variable, VariableModel<Variable, Type>> newVariableInfo) {
     if (first.reachable == newReachable &&
         identical(first.variableInfo, newVariableInfo)) {
       return first;
@@ -1831,7 +1837,7 @@
   ///
   /// The equivalence check is shallow; if two variables' models are not
   /// identical, we return `false`.
-  static bool _variableInfosEqual<Variable, Type>(
+  static bool _variableInfosEqual<Variable extends Object, Type extends Object>(
       Map<Variable, VariableModel<Variable, Type>> p1,
       Map<Variable, VariableModel<Variable, Type>> p2) {
     if (p1.length != p2.length) return false;
@@ -1839,7 +1845,7 @@
     for (MapEntry<Variable, VariableModel<Variable, Type>> entry
         in p1.entries) {
       VariableModel<Variable, Type> p1Value = entry.value;
-      VariableModel<Variable, Type> p2Value = p2[entry.key];
+      VariableModel<Variable, Type>? p2Value = p2[entry.key];
       if (!identical(p1Value, p2Value)) {
         return false;
       }
@@ -1863,7 +1869,7 @@
   /// if there is no checkpoint.  Reachabilities form a tree structure that
   /// mimics the control flow of the code being analyzed, so this is called the
   /// "parent".
-  final Reachability parent;
+  final Reachability? parent;
 
   /// Whether this point in the source code is considered reachable from the
   /// most recent checkpoint.
@@ -1898,7 +1904,7 @@
   @override
   String toString() {
     List<bool> values = [];
-    for (Reachability node = this; node != null; node = node.parent) {
+    for (Reachability? node = this; node != null; node = node.parent) {
       values.add(node.locallyReachable);
     }
     return '[${values.join(', ')}]';
@@ -1908,9 +1914,9 @@
   /// the same notion of reachability relative to the previous two checkpoints.
   Reachability unsplit() {
     if (locallyReachable) {
-      return parent;
+      return parent!;
     } else {
-      return parent.setUnreachable();
+      return parent!.setUnreachable();
     }
   }
 
@@ -1958,7 +1964,7 @@
 }
 
 /// Operations on types, abstracted from concrete type interfaces.
-abstract class TypeOperations<Variable, Type> {
+abstract class TypeOperations<Variable extends Object, Type extends Object> {
   /// Classifies the given type into one of the three categories defined by
   /// the [TypeClassification] enum.
   TypeClassification classifyType(Type type);
@@ -1973,8 +1979,8 @@
   ///
   /// It is not expected that any implementation would override this except for
   /// the migration engine.
-  bool forcePromotion(Type to, Type from, List<Type> promotedTypes,
-          List<Type> newPromotedTypes) =>
+  bool forcePromotion(Type to, Type from, List<Type>? promotedTypes,
+          List<Type>? newPromotedTypes) =>
       false;
 
   /// Determines whether the given [type] is equivalent to the `Never` type.
@@ -2002,13 +2008,13 @@
   ///
   /// It is not expected that any implementation would override this except for
   /// the migration engine.
-  List<Type> refinePromotedTypes(
-          List<Type> chain1, List<Type> chain2, List<Type> promotedTypes) =>
+  List<Type>? refinePromotedTypes(
+          List<Type>? chain1, List<Type>? chain2, List<Type>? promotedTypes) =>
       promotedTypes;
 
   /// Tries to promote to the first type from the second type, and returns the
   /// promoted type if it succeeds, otherwise null.
-  Type tryPromoteToType(Type to, Type from);
+  Type? tryPromoteToType(Type to, Type from);
 
   /// Return the static type of the given [variable].
   Type variableType(Variable variable);
@@ -2021,11 +2027,11 @@
 /// Instances of this class are immutable, so the methods below that "update"
 /// the state actually leave `this` unchanged and return a new state object.
 @visibleForTesting
-class VariableModel<Variable, Type> {
+class VariableModel<Variable extends Object, Type extends Object> {
   /// Sequence of types that the variable has been promoted to, where each
   /// element of the sequence is a subtype of the previous.  Null if the
   /// variable hasn't been promoted.
-  final List<Type> promotedTypes;
+  final List<Type>? promotedTypes;
 
   /// List of types that the variable has been tested against in all code paths
   /// leading to the given point in the source code.
@@ -2044,11 +2050,12 @@
       this.writeCaptured) {
     assert(!(assigned && unassigned),
         "Can't be both definitely assigned and unassigned");
-    assert(promotedTypes == null || promotedTypes.isNotEmpty);
+    assert(promotedTypes == null || promotedTypes!.isNotEmpty);
     assert(!writeCaptured || promotedTypes == null,
         "Write-captured variables can't be promoted");
     assert(!(writeCaptured && unassigned),
         "Write-captured variables can't be definitely unassigned");
+    // ignore:unnecessary_null_comparison
     assert(tested != null);
   }
 
@@ -2077,8 +2084,8 @@
       TypeOperations<Variable, Type> typeOperations,
       VariableModel<Variable, Type> otherModel,
       bool unsafe) {
-    List<Type> thisPromotedTypes = promotedTypes;
-    List<Type> otherPromotedTypes = otherModel.promotedTypes;
+    List<Type>? thisPromotedTypes = promotedTypes;
+    List<Type>? otherPromotedTypes = otherModel.promotedTypes;
     bool newAssigned = assigned || otherModel.assigned;
     // The variable can only be unassigned in this state if it was also
     // unassigned in the other state or if the other state didn't complete
@@ -2101,7 +2108,7 @@
     //
     bool newUnassigned = unassigned && otherModel.unassigned;
     bool newWriteCaptured = writeCaptured || otherModel.writeCaptured;
-    List<Type> newPromotedTypes;
+    List<Type>? newPromotedTypes;
     if (newWriteCaptured) {
       // Write-captured variables can't be promoted
       newPromotedTypes = null;
@@ -2167,7 +2174,7 @@
           promotedTypes, tested, true, false, writeCaptured);
     }
 
-    List<Type> newPromotedTypes = _demoteViaAssignment(
+    List<Type>? newPromotedTypes = _demoteViaAssignment(
       writtenType,
       typeOperations,
     );
@@ -2195,10 +2202,11 @@
         null, const [], assigned, false, true);
   }
 
-  List<Type> _demoteViaAssignment(
+  List<Type>? _demoteViaAssignment(
     Type writtenType,
     TypeOperations<Variable, Type> typeOperations,
   ) {
+    List<Type>? promotedTypes = this.promotedTypes;
     if (promotedTypes == null) {
       return null;
     }
@@ -2225,10 +2233,10 @@
   ///
   /// Note that since promotion chains are considered immutable, if promotion
   /// is required, a new promotion chain will be created and returned.
-  List<Type> _tryPromoteToTypeOfInterest(
+  List<Type>? _tryPromoteToTypeOfInterest(
       TypeOperations<Variable, Type> typeOperations,
       Type declaredType,
-      List<Type> promotedTypes,
+      List<Type>? promotedTypes,
       Type writtenType) {
     assert(!writeCaptured);
 
@@ -2240,10 +2248,10 @@
     // Figure out if we have any promotion candidates (types that are a
     // supertype of writtenType and a proper subtype of the currently-promoted
     // type).  If at any point we find an exact match, we take it immediately.
-    Type currentlyPromotedType = promotedTypes?.last;
+    Type? currentlyPromotedType = promotedTypes?.last;
 
-    List<Type> result;
-    List<Type> candidates = null;
+    List<Type>? result;
+    List<Type>? candidates = null;
 
     void handleTypeOfInterest(Type type) {
       // The written type must be a subtype of the type.
@@ -2272,8 +2280,8 @@
       }
 
       // Add only unique candidates.
-      if (!_typeListContains(typeOperations, candidates, type)) {
-        candidates.add(type);
+      if (!_typeListContains(typeOperations, candidates!, type)) {
+        candidates!.add(type);
         return;
       }
     }
@@ -2284,7 +2292,7 @@
     if (!typeOperations.isSameType(declaredTypeNonNull, declaredType)) {
       handleTypeOfInterest(declaredTypeNonNull);
       if (result != null) {
-        return result;
+        return result!;
       }
     }
 
@@ -2293,27 +2301,28 @@
 
       handleTypeOfInterest(type);
       if (result != null) {
-        return result;
+        return result!;
       }
 
       Type typeNonNull = typeOperations.promoteToNonNull(type);
       if (!typeOperations.isSameType(typeNonNull, type)) {
         handleTypeOfInterest(typeNonNull);
         if (result != null) {
-          return result;
+          return result!;
         }
       }
     }
 
-    if (candidates != null) {
+    List<Type>? candidates2 = candidates;
+    if (candidates2 != null) {
       // Figure out if we have a unique promotion candidate that's a subtype
       // of all the others.
-      Type promoted;
+      Type? promoted;
       outer:
-      for (int i = 0; i < candidates.length; i++) {
-        for (int j = 0; j < candidates.length; j++) {
+      for (int i = 0; i < candidates2.length; i++) {
+        for (int j = 0; j < candidates2.length; j++) {
           if (j == i) continue;
-          if (!typeOperations.isSubtypeOf(candidates[i], candidates[j])) {
+          if (!typeOperations.isSubtypeOf(candidates2[i], candidates2[j])) {
             // Not a subtype of all the others.
             continue outer;
           }
@@ -2322,7 +2331,7 @@
           // Not unique.  Do not promote.
           return promotedTypes;
         } else {
-          promoted = candidates[i];
+          promoted = candidates2[i];
         }
       }
       if (promoted != null) {
@@ -2339,10 +2348,11 @@
   /// are consistently treated as "of interest" in code that follows the loop,
   /// regardless of the type of loop.
   @visibleForTesting
-  static VariableModel<Variable, Type> inheritTested<Variable, Type>(
-      TypeOperations<Variable, Type> typeOperations,
-      VariableModel<Variable, Type> model,
-      List<Type> tested) {
+  static VariableModel<Variable, Type>
+      inheritTested<Variable extends Object, Type extends Object>(
+          TypeOperations<Variable, Type> typeOperations,
+          VariableModel<Variable, Type> model,
+          List<Type> tested) {
     List<Type> newTested = joinTested(tested, model.tested, typeOperations);
     if (identical(newTested, model.tested)) return model;
     return new VariableModel<Variable, Type>(model.promotedTypes, newTested,
@@ -2350,11 +2360,12 @@
   }
 
   /// Joins two variable models.  See [FlowModel.join] for details.
-  static VariableModel<Variable, Type> join<Variable, Type>(
-      TypeOperations<Variable, Type> typeOperations,
-      VariableModel<Variable, Type> first,
-      VariableModel<Variable, Type> second) {
-    List<Type> newPromotedTypes = joinPromotedTypes(
+  static VariableModel<Variable, Type>
+      join<Variable extends Object, Type extends Object>(
+          TypeOperations<Variable, Type> typeOperations,
+          VariableModel<Variable, Type> first,
+          VariableModel<Variable, Type> second) {
+    List<Type>? newPromotedTypes = joinPromotedTypes(
         first.promotedTypes, second.promotedTypes, typeOperations);
     newPromotedTypes = typeOperations.refinePromotedTypes(
         first.promotedTypes, second.promotedTypes, newPromotedTypes);
@@ -2372,8 +2383,11 @@
   /// chains.  Briefly, we intersect given chains.  The chains are totally
   /// ordered subsets of a global partial order.  Their intersection is a
   /// subset of each, and as such is also totally ordered.
-  static List<Type> joinPromotedTypes<Variable, Type>(List<Type> chain1,
-      List<Type> chain2, TypeOperations<Variable, Type> typeOperations) {
+  static List<Type>?
+      joinPromotedTypes<Variable extends Object, Type extends Object>(
+          List<Type>? chain1,
+          List<Type>? chain2,
+          TypeOperations<Variable, Type> typeOperations) {
     if (chain1 == null) return chain1;
     if (chain2 == null) return chain2;
 
@@ -2381,7 +2395,7 @@
     int index2 = 0;
     bool skipped1 = false;
     bool skipped2 = false;
-    List<Type> result;
+    List<Type>? result;
     while (index1 < chain1.length && index2 < chain2.length) {
       Type type1 = chain1[index1];
       Type type2 = chain2[index2];
@@ -2416,8 +2430,10 @@
   /// - The sense of equality for the union operation is determined by
   ///   [TypeOperations.isSameType].
   /// - The types of interests lists are considered immutable.
-  static List<Type> joinTested<Variable, Type>(List<Type> types1,
-      List<Type> types2, TypeOperations<Variable, Type> typeOperations) {
+  static List<Type> joinTested<Variable extends Object, Type extends Object>(
+      List<Type> types1,
+      List<Type> types2,
+      TypeOperations<Variable, Type> typeOperations) {
     // Ensure that types1 is the shorter list.
     if (types1.length > types2.length) {
       List<Type> tmp = types1;
@@ -2446,28 +2462,32 @@
     return types2;
   }
 
-  static List<Type> _addToPromotedTypes<Type>(
-          List<Type> promotedTypes, Type promoted) =>
+  static List<Type> _addToPromotedTypes<Type extends Object>(
+          List<Type>? promotedTypes, Type promoted) =>
       promotedTypes == null
           ? [promoted]
           : (promotedTypes.toList()..add(promoted));
 
-  static List<Type> _addTypeToUniqueList<Variable, Type>(List<Type> types,
-      Type newType, TypeOperations<Variable, Type> typeOperations) {
+  static List<Type>
+      _addTypeToUniqueList<Variable extends Object, Type extends Object>(
+          List<Type> types,
+          Type newType,
+          TypeOperations<Variable, Type> typeOperations) {
     if (_typeListContains(typeOperations, types, newType)) return types;
     return new List<Type>.from(types)..add(newType);
   }
 
   /// Creates a new [VariableModel] object, unless it is equivalent to either
   /// [first] or [second], in which case one of those objects is re-used.
-  static VariableModel<Variable, Type> _identicalOrNew<Variable, Type>(
-      VariableModel<Variable, Type> first,
-      VariableModel<Variable, Type> second,
-      List<Type> newPromotedTypes,
-      List<Type> newTested,
-      bool newAssigned,
-      bool newUnassigned,
-      bool newWriteCaptured) {
+  static VariableModel<Variable, Type>
+      _identicalOrNew<Variable extends Object, Type extends Object>(
+          VariableModel<Variable, Type> first,
+          VariableModel<Variable, Type> second,
+          List<Type>? newPromotedTypes,
+          List<Type> newTested,
+          bool newAssigned,
+          bool newUnassigned,
+          bool newWriteCaptured) {
     if (identical(first.promotedTypes, newPromotedTypes) &&
         identical(first.tested, newTested) &&
         first.assigned == newAssigned &&
@@ -2486,7 +2506,7 @@
     }
   }
 
-  static bool _typeListContains<Variable, Type>(
+  static bool _typeListContains<Variable extends Object, Type extends Object>(
       TypeOperations<Variable, Type> typeOperations,
       List<Type> list,
       Type searchType) {
@@ -2498,9 +2518,10 @@
 }
 
 /// [_FlowContext] representing an assert statement or assert initializer.
-class _AssertContext<Variable, Type> extends _SimpleContext<Variable, Type> {
+class _AssertContext<Variable extends Object, Type extends Object>
+    extends _SimpleContext<Variable, Type> {
   /// Flow models associated with the condition being asserted.
-  ExpressionInfo<Variable, Type> _conditionInfo;
+  ExpressionInfo<Variable, Type>? _conditionInfo;
 
   _AssertContext(FlowModel<Variable, Type> previous) : super(previous);
 
@@ -2512,9 +2533,10 @@
 /// [_FlowContext] representing a language construct that branches on a boolean
 /// condition, such as an `if` statement, conditional expression, or a logical
 /// binary operator.
-class _BranchContext<Variable, Type> extends _FlowContext {
+class _BranchContext<Variable extends Object, Type extends Object>
+    extends _FlowContext {
   /// Flow models associated with the condition being branched on.
-  final ExpressionInfo<Variable, Type> _conditionInfo;
+  final ExpressionInfo<Variable, Type>? _conditionInfo;
 
   _BranchContext(this._conditionInfo);
 
@@ -2524,14 +2546,15 @@
 
 /// [_FlowContext] representing a language construct that can be targeted by
 /// `break` or `continue` statements, such as a loop or switch statement.
-class _BranchTargetContext<Variable, Type> extends _FlowContext {
+class _BranchTargetContext<Variable extends Object, Type extends Object>
+    extends _FlowContext {
   /// Accumulated flow model for all `break` statements seen so far, or `null`
   /// if no `break` statements have been seen yet.
-  FlowModel<Variable, Type> _breakModel;
+  FlowModel<Variable, Type>? _breakModel;
 
   /// Accumulated flow model for all `continue` statements seen so far, or
   /// `null` if no `continue` statements have been seen yet.
-  FlowModel<Variable, Type> _continueModel;
+  FlowModel<Variable, Type>? _continueModel;
 
   /// The reachability checkpoint associated with this loop or switch statement.
   /// When analyzing deeply nested `break` and `continue` statements, their flow
@@ -2547,11 +2570,11 @@
 }
 
 /// [_FlowContext] representing a conditional expression.
-class _ConditionalContext<Variable, Type>
+class _ConditionalContext<Variable extends Object, Type extends Object>
     extends _BranchContext<Variable, Type> {
   /// Flow models associated with the value of the conditional expression in the
   /// circumstance where the "then" branch is taken.
-  ExpressionInfo<Variable, Type> _thenInfo;
+  ExpressionInfo<Variable, Type>? _thenInfo;
 
   _ConditionalContext(ExpressionInfo<Variable, Type> conditionInfo)
       : super(conditionInfo);
@@ -2562,15 +2585,16 @@
 }
 
 /// [_FlowContext] representing an equality comparison using `==` or `!=`.
-class _EqualityOpContext<Variable, Type> extends _BranchContext {
+class _EqualityOpContext<Variable extends Object, Type extends Object>
+    extends _BranchContext<Variable, Type> {
   /// The type of the expression on the LHS of `==` or `!=`.
   final Type _leftOperandType;
 
   /// If the LHS of `==` or `!=` is a variable reference, the variable.
   /// Otherwise `null`.
-  final Variable _leftOperandVariable;
+  final Variable? _leftOperandVariable;
 
-  _EqualityOpContext(ExpressionInfo<Variable, Type> conditionInfo,
+  _EqualityOpContext(ExpressionInfo<Variable, Type>? conditionInfo,
       this._leftOperandType, this._leftOperandVariable)
       : super(conditionInfo);
 
@@ -2580,8 +2604,9 @@
       '$_leftOperandType)';
 }
 
-class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
-    Type> implements FlowAnalysis<Node, Statement, Expression, Variable, Type> {
+class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
+        Expression extends Object, Variable extends Object, Type extends Object>
+    implements FlowAnalysis<Node, Statement, Expression, Variable, Type> {
   /// The [TypeOperations], used to access types, and check subtyping.
   final TypeOperations<Variable, Type> typeOperations;
 
@@ -2595,24 +2620,24 @@
   final Map<Statement, _BranchTargetContext<Variable, Type>>
       _statementToContext = {};
 
-  FlowModel<Variable, Type> _current;
+  late FlowModel<Variable, Type> _current;
 
   /// The most recently visited expression for which an [ExpressionInfo] object
   /// exists, or `null` if no expression has been visited that has a
   /// corresponding [ExpressionInfo] object.
-  Expression _expressionWithInfo;
+  Expression? _expressionWithInfo;
 
   /// If [_expressionWithInfo] is not `null`, the [ExpressionInfo] object
   /// corresponding to it.  Otherwise `null`.
-  ExpressionInfo<Variable, Type> _expressionInfo;
+  ExpressionInfo<Variable, Type>? _expressionInfo;
 
   /// The most recently visited expression which was a variable reference, or
   /// `null` if no expression has been visited that was a variable reference.
-  Expression _expressionWithVariable;
+  Expression? _expressionWithVariable;
 
   /// If [_expressionVariable] is not `null`, the variable corresponding to it.
   /// Otherwise `null`.
-  Variable _expressionVariable;
+  Variable? _expressionVariable;
 
   int _functionNestingLevel = 0;
 
@@ -2627,7 +2652,7 @@
 
   @override
   void asExpression_end(Expression subExpression, Type type) {
-    Variable variable = _getExpressionVariable(subExpression);
+    Variable? variable = _getExpressionVariable(subExpression);
     if (variable == null) return;
     _current = _current.tryPromoteForTypeCast(typeOperations, variable, type);
   }
@@ -2651,7 +2676,7 @@
   void assert_end() {
     _AssertContext<Variable, Type> context =
         _stack.removeLast() as _AssertContext<Variable, Type>;
-    _current = _merge(context._previous, context._conditionInfo.ifTrue);
+    _current = _merge(context._previous, context._conditionInfo!.ifTrue);
   }
 
   @override
@@ -2674,7 +2699,7 @@
     _ConditionalContext<Variable, Type> context =
         _stack.last as _ConditionalContext<Variable, Type>;
     context._thenInfo = _expressionEnd(thenExpression);
-    _current = context._conditionInfo.ifFalse;
+    _current = context._conditionInfo!.ifFalse;
   }
 
   @override
@@ -2682,7 +2707,7 @@
       Expression conditionalExpression, Expression elseExpression) {
     _ConditionalContext<Variable, Type> context =
         _stack.removeLast() as _ConditionalContext<Variable, Type>;
-    ExpressionInfo<Variable, Type> thenInfo = context._thenInfo;
+    ExpressionInfo<Variable, Type> thenInfo = context._thenInfo!;
     ExpressionInfo<Variable, Type> elseInfo = _expressionEnd(elseExpression);
     _storeExpressionInfo(
         conditionalExpression,
@@ -2735,11 +2760,11 @@
       {bool notEqual = false}) {
     _EqualityOpContext<Variable, Type> context =
         _stack.removeLast() as _EqualityOpContext<Variable, Type>;
-    ExpressionInfo<Variable, Type> lhsInfo = context._conditionInfo;
-    Variable lhsVariable = context._leftOperandVariable;
+    ExpressionInfo<Variable, Type>? lhsInfo = context._conditionInfo;
+    Variable? lhsVariable = context._leftOperandVariable;
     Type leftOperandType = context._leftOperandType;
-    ExpressionInfo<Variable, Type> rhsInfo = _getExpressionInfo(rightOperand);
-    Variable rhsVariable = _getExpressionVariable(rightOperand);
+    ExpressionInfo<Variable, Type>? rhsInfo = _getExpressionInfo(rightOperand);
+    Variable? rhsVariable = _getExpressionVariable(rightOperand);
     TypeClassification leftOperandTypeClassification =
         typeOperations.classifyType(leftOperandType);
     TypeClassification rightOperandTypeClassification =
@@ -2787,12 +2812,12 @@
   }
 
   @override
-  void for_bodyBegin(Statement node, Expression condition) {
+  void for_bodyBegin(Statement? node, Expression? condition) {
     ExpressionInfo<Variable, Type> conditionInfo = condition == null
         ? new ExpressionInfo(_current, _current, _current.setUnreachable())
         : _expressionEnd(condition);
     _WhileContext<Variable, Type> context = new _WhileContext<Variable, Type>(
-        _current.reachable.parent, conditionInfo);
+        _current.reachable.parent!, conditionInfo);
     _stack.add(context);
     if (node != null) {
       _statementToContext[node] = context;
@@ -2812,7 +2837,7 @@
     _WhileContext<Variable, Type> context =
         _stack.removeLast() as _WhileContext<Variable, Type>;
     // Tail of the stack: falseCondition, break
-    FlowModel<Variable, Type> breakState = context._breakModel;
+    FlowModel<Variable, Type>? breakState = context._breakModel;
     FlowModel<Variable, Type> falseCondition = context._conditionInfo.ifFalse;
 
     _current = _merge(falseCondition, breakState)
@@ -2827,13 +2852,13 @@
   }
 
   @override
-  void forEach_bodyBegin(Node node, Variable loopVariable, Type writtenType) {
+  void forEach_bodyBegin(Node node, Variable? loopVariable, Type writtenType) {
     AssignedVariablesNodeInfo<Variable> info =
         _assignedVariables._getInfoForNode(node);
     _current = _current.conservativeJoin(info._written, info._captured).split();
     _SimpleStatementContext<Variable, Type> context =
         new _SimpleStatementContext<Variable, Type>(
-            _current.reachable.parent, _current);
+            _current.reachable.parent!, _current);
     _stack.add(context);
     if (loopVariable != null) {
       _current = _current.write(loopVariable, writtenType, typeOperations);
@@ -2879,7 +2904,7 @@
 
   @override
   void handleBreak(Statement target) {
-    _BranchTargetContext<Variable, Type> context = _statementToContext[target];
+    _BranchTargetContext<Variable, Type>? context = _statementToContext[target];
     if (context != null) {
       context._breakModel =
           _join(context._breakModel, _current.unsplitTo(context._checkpoint));
@@ -2889,7 +2914,7 @@
 
   @override
   void handleContinue(Statement target) {
-    _BranchTargetContext<Variable, Type> context = _statementToContext[target];
+    _BranchTargetContext<Variable, Type>? context = _statementToContext[target];
     if (context != null) {
       context._continueModel = _join(
           context._continueModel, _current.unsplitTo(context._checkpoint));
@@ -2912,7 +2937,7 @@
   @override
   void ifNullExpression_rightBegin(
       Expression leftHandSide, Type leftHandSideType) {
-    Variable lhsVariable = _getExpressionVariable(leftHandSide);
+    Variable? lhsVariable = _getExpressionVariable(leftHandSide);
     FlowModel<Variable, Type> promoted;
     _current = _current.split();
     if (lhsVariable != null) {
@@ -2936,7 +2961,7 @@
     _IfContext<Variable, Type> context =
         _stack.last as _IfContext<Variable, Type>;
     context._afterThen = _current;
-    _current = context._conditionInfo.ifFalse;
+    _current = context._conditionInfo!.ifFalse;
   }
 
   @override
@@ -2946,11 +2971,11 @@
     FlowModel<Variable, Type> afterThen;
     FlowModel<Variable, Type> afterElse;
     if (hasElse) {
-      afterThen = context._afterThen;
+      afterThen = context._afterThen!;
       afterElse = _current;
     } else {
       afterThen = _current; // no `else`, so `then` is still current
-      afterElse = context._conditionInfo.ifFalse;
+      afterElse = context._conditionInfo!.ifFalse;
     }
     _current = _merge(afterThen, afterElse);
   }
@@ -2970,7 +2995,7 @@
   @override
   void isExpression_end(Expression isExpression, Expression subExpression,
       bool isNot, Type type) {
-    Variable subExpressionVariable = _getExpressionVariable(subExpression);
+    Variable? subExpressionVariable = _getExpressionVariable(subExpression);
     if (subExpressionVariable != null) {
       ExpressionInfo<Variable, Type> expressionInfo = _current
           .tryPromoteForTypeCheck(typeOperations, subExpressionVariable, type);
@@ -2985,10 +3010,10 @@
   }
 
   @override
-  void labeledStatement_begin(Node node) {
+  void labeledStatement_begin(Statement node) {
     _current = _current.split();
     _BranchTargetContext<Variable, Type> context =
-        new _BranchTargetContext<Variable, Type>(_current.reachable.parent);
+        new _BranchTargetContext<Variable, Type>(_current.reachable.parent!);
     _stack.add(context);
     _statementToContext[node] = context;
   }
@@ -3027,7 +3052,7 @@
 
   @override
   void logicalBinaryOp_end(Expression wholeExpression, Expression rightOperand,
-      {@required bool isAnd}) {
+      {required bool isAnd}) {
     _BranchContext<Variable, Type> context =
         _stack.removeLast() as _BranchContext<Variable, Type>;
     ExpressionInfo<Variable, Type> rhsInfo = _expressionEnd(rightOperand);
@@ -3036,9 +3061,9 @@
     FlowModel<Variable, Type> falseResult;
     if (isAnd) {
       trueResult = rhsInfo.ifTrue;
-      falseResult = _join(context._conditionInfo.ifFalse, rhsInfo.ifFalse);
+      falseResult = _join(context._conditionInfo!.ifFalse, rhsInfo.ifFalse);
     } else {
-      trueResult = _join(context._conditionInfo.ifTrue, rhsInfo.ifTrue);
+      trueResult = _join(context._conditionInfo!.ifTrue, rhsInfo.ifTrue);
       falseResult = rhsInfo.ifFalse;
     }
     _storeExpressionInfo(
@@ -3049,7 +3074,7 @@
 
   @override
   void logicalBinaryOp_rightBegin(Expression leftOperand,
-      {@required bool isAnd}) {
+      {required bool isAnd}) {
     ExpressionInfo<Variable, Type> conditionInfo = _expressionEnd(leftOperand);
     _stack.add(new _BranchContext<Variable, Type>(conditionInfo));
     _current = isAnd ? conditionInfo.ifTrue : conditionInfo.ifFalse;
@@ -3063,7 +3088,7 @@
 
   @override
   void nonNullAssert_end(Expression operand) {
-    Variable operandVariable = _getExpressionVariable(operand);
+    Variable? operandVariable = _getExpressionVariable(operand);
     if (operandVariable != null) {
       _current =
           _current.tryMarkNonNullable(typeOperations, operandVariable).ifTrue;
@@ -3078,16 +3103,15 @@
   }
 
   @override
-  void nullAwareAccess_rightBegin(Expression target, Type targetType) {
+  void nullAwareAccess_rightBegin(Expression? target, Type targetType) {
+    // ignore:unnecessary_null_comparison
     assert(targetType != null);
     _current = _current.split();
     _stack.add(new _NullAwareAccessContext<Variable, Type>(_current));
-    if (target != null) {
-      Variable targetVariable = _getExpressionVariable(target);
-      if (targetVariable != null) {
-        _current =
-            _current.tryMarkNonNullable(typeOperations, targetVariable).ifTrue;
-      }
+    Variable? targetVariable = _getExpressionVariable(target);
+    if (targetVariable != null) {
+      _current =
+          _current.tryMarkNonNullable(typeOperations, targetVariable).ifTrue;
     }
   }
 
@@ -3109,7 +3133,7 @@
   }
 
   @override
-  Type promotedType(Variable variable) {
+  Type? promotedType(Variable variable) {
     return _current.infoFor(variable).promotedTypes?.last;
   }
 
@@ -3131,7 +3155,7 @@
   void switchStatement_end(bool isExhaustive) {
     _SimpleStatementContext<Variable, Type> context =
         _stack.removeLast() as _SimpleStatementContext<Variable, Type>;
-    FlowModel<Variable, Type> breakState = context._breakModel;
+    FlowModel<Variable, Type>? breakState = context._breakModel;
 
     // It is allowed to "fall off" the end of a switch statement, so join the
     // current state to any breaks that were found previously.
@@ -3148,7 +3172,7 @@
     _current = _current.split();
     _SimpleStatementContext<Variable, Type> context =
         new _SimpleStatementContext<Variable, Type>(
-            _current.reachable.parent, _current);
+            _current.reachable.parent!, _current);
     _stack.add(context);
     _statementToContext[switchStatement] = context;
   }
@@ -3178,10 +3202,10 @@
 
   @override
   void tryCatchStatement_catchBegin(
-      Variable exceptionVariable, Variable stackTraceVariable) {
+      Variable? exceptionVariable, Variable? stackTraceVariable) {
     _TryContext<Variable, Type> context =
         _stack.last as _TryContext<Variable, Type>;
-    _current = context._beforeCatch;
+    _current = context._beforeCatch!;
     if (exceptionVariable != null) {
       _current = _current.declare(exceptionVariable, true);
     }
@@ -3202,7 +3226,7 @@
   void tryCatchStatement_end() {
     _TryContext<Variable, Type> context =
         _stack.removeLast() as _TryContext<Variable, Type>;
-    _current = context._afterBodyAndCatches.unsplit();
+    _current = context._afterBodyAndCatches!.unsplit();
   }
 
   @override
@@ -3217,7 +3241,7 @@
     _TryContext<Variable, Type> context =
         _stack.removeLast() as _TryContext<Variable, Type>;
     _current = _current.restrict(
-        typeOperations, context._afterBodyAndCatches, info._written);
+        typeOperations, context._afterBodyAndCatches!, info._written);
   }
 
   @override
@@ -3232,7 +3256,7 @@
   }
 
   @override
-  Type variableRead(Expression expression, Variable variable) {
+  Type? variableRead(Expression expression, Variable variable) {
     _storeExpressionVariable(expression, variable);
     return _current.infoFor(variable).promotedTypes?.last;
   }
@@ -3242,7 +3266,7 @@
       Statement whileStatement, Expression condition) {
     ExpressionInfo<Variable, Type> conditionInfo = _expressionEnd(condition);
     _WhileContext<Variable, Type> context = new _WhileContext<Variable, Type>(
-        _current.reachable.parent, conditionInfo);
+        _current.reachable.parent!, conditionInfo);
     _stack.add(context);
     _statementToContext[whileStatement] = context;
     _current = conditionInfo.ifTrue;
@@ -3300,9 +3324,9 @@
   /// be the last expression that was traversed).  If there is no
   /// [ExpressionInfo] associated with the [expression], then `null` is
   /// returned.
-  ExpressionInfo<Variable, Type> _getExpressionInfo(Expression expression) {
+  ExpressionInfo<Variable, Type>? _getExpressionInfo(Expression expression) {
     if (identical(expression, _expressionWithInfo)) {
-      ExpressionInfo<Variable, Type> expressionInfo = _expressionInfo;
+      ExpressionInfo<Variable, Type>? expressionInfo = _expressionInfo;
       _expressionInfo = null;
       return expressionInfo;
     } else {
@@ -3313,9 +3337,9 @@
   /// Gets the [Variable] associated with the [expression] (which should be the
   /// last expression that was traversed).  If there is no [Variable] associated
   /// with the [expression], then `null` is returned.
-  Variable _getExpressionVariable(Expression expression) {
+  Variable? _getExpressionVariable(Expression? expression) {
     if (identical(expression, _expressionWithVariable)) {
-      Variable expressionVariable = _expressionVariable;
+      Variable? expressionVariable = _expressionVariable;
       _expressionVariable = null;
       return expressionVariable;
     } else {
@@ -3323,12 +3347,12 @@
     }
   }
 
-  FlowModel<Variable, Type> _join(
-          FlowModel<Variable, Type> first, FlowModel<Variable, Type> second) =>
+  FlowModel<Variable, Type> _join(FlowModel<Variable, Type>? first,
+          FlowModel<Variable, Type>? second) =>
       FlowModel.join(typeOperations, first, second, _current._emptyVariableMap);
 
   FlowModel<Variable, Type> _merge(
-          FlowModel<Variable, Type> first, FlowModel<Variable, Type> second) =>
+          FlowModel<Variable, Type> first, FlowModel<Variable, Type>? second) =>
       FlowModel.merge(
           typeOperations, first, second, _current._emptyVariableMap);
 
@@ -3356,7 +3380,7 @@
 abstract class _FlowContext {}
 
 /// [_FlowContext] representing a function expression.
-class _FunctionExpressionContext<Variable, Type>
+class _FunctionExpressionContext<Variable extends Object, Type extends Object>
     extends _SimpleContext<Variable, Type> {
   _FunctionExpressionContext(FlowModel<Variable, Type> previous)
       : super(previous);
@@ -3366,10 +3390,11 @@
 }
 
 /// [_FlowContext] representing an `if` statement.
-class _IfContext<Variable, Type> extends _BranchContext<Variable, Type> {
+class _IfContext<Variable extends Object, Type extends Object>
+    extends _BranchContext<Variable, Type> {
   /// Flow model associated with the state of program execution after the `if`
   /// statement executes, in the circumstance where the "then" branch is taken.
-  FlowModel<Variable, Type> _afterThen;
+  FlowModel<Variable, Type>? _afterThen;
 
   _IfContext(ExpressionInfo<Variable, Type> conditionInfo)
       : super(conditionInfo);
@@ -3380,7 +3405,7 @@
 }
 
 /// [_FlowContext] representing an "if-null" (`??`) expression.
-class _IfNullExpressionContext<Variable, Type>
+class _IfNullExpressionContext<Variable extends Object, Type extends Object>
     extends _SimpleContext<Variable, Type> {
   _IfNullExpressionContext(FlowModel<Variable, Type> previous)
       : super(previous);
@@ -3390,7 +3415,7 @@
 }
 
 /// [_FlowContext] representing a null aware access (`?.`).
-class _NullAwareAccessContext<Variable, Type>
+class _NullAwareAccessContext<Variable extends Object, Type extends Object>
     extends _SimpleContext<Variable, Type> {
   _NullAwareAccessContext(FlowModel<Variable, Type> previous) : super(previous);
 
@@ -3399,7 +3424,8 @@
 }
 
 /// [ExpressionInfo] representing a `null` literal.
-class _NullInfo<Variable, Type> implements ExpressionInfo<Variable, Type> {
+class _NullInfo<Variable extends Object, Type extends Object>
+    implements ExpressionInfo<Variable, Type> {
   @override
   final FlowModel<Variable, Type> after;
 
@@ -3415,7 +3441,8 @@
 /// [_FlowContext] representing a language construct for which flow analysis
 /// must store a flow model state to be retrieved later, such as a `try`
 /// statement, function expression, or "if-null" (`??`) expression.
-abstract class _SimpleContext<Variable, Type> extends _FlowContext {
+abstract class _SimpleContext<Variable extends Object, Type extends Object>
+    extends _FlowContext {
   /// The stored state.  For a `try` statement, this is the state from the
   /// beginning of the `try` block.  For a function expression, this is the
   /// state at the point the function expression was created.  For an "if-null"
@@ -3430,7 +3457,7 @@
 /// `break` or `continue` statements, and for which flow analysis must store a
 /// flow model state to be retrieved later.  Examples include "for each" and
 /// `switch` statements.
-class _SimpleStatementContext<Variable, Type>
+class _SimpleStatementContext<Variable extends Object, Type extends Object>
     extends _BranchTargetContext<Variable, Type> {
   /// The stored state.  For a "for each" statement, this is the state after
   /// evaluation of the iterable.  For a `switch` statement, this is the state
@@ -3447,17 +3474,18 @@
 }
 
 /// [_FlowContext] representing a try statement.
-class _TryContext<Variable, Type> extends _SimpleContext<Variable, Type> {
+class _TryContext<Variable extends Object, Type extends Object>
+    extends _SimpleContext<Variable, Type> {
   /// If the statement is a "try/catch" statement, the flow model representing
   /// program state at the top of any `catch` block.
-  FlowModel<Variable, Type> _beforeCatch;
+  FlowModel<Variable, Type>? _beforeCatch;
 
   /// If the statement is a "try/catch" statement, the accumulated flow model
   /// representing program state after the `try` block or one of the `catch`
   /// blocks has finished executing.  If the statement is a "try/finally"
   /// statement, the flow model representing program state after the `try` block
   /// has finished executing.
-  FlowModel<Variable, Type> _afterBodyAndCatches;
+  FlowModel<Variable, Type>? _afterBodyAndCatches;
 
   _TryContext(FlowModel<Variable, Type> previous) : super(previous);
 
@@ -3469,7 +3497,7 @@
 
 /// [_FlowContext] representing a `while` loop (or a C-style `for` loop, which
 /// is functionally similar).
-class _WhileContext<Variable, Type>
+class _WhileContext<Variable extends Object, Type extends Object>
     extends _BranchTargetContext<Variable, Type> {
   /// Flow models associated with the loop condition.
   final ExpressionInfo<Variable, Type> _conditionInfo;
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes.dart
index 5d95d3b..395c60d 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes.dart
@@ -26,15 +26,12 @@
   /// this error to its corresponding Analyzer error.
   final int index;
 
-  final Template<T> template;
-
-  final List<String> analyzerCodes;
+  final List<String>? analyzerCodes;
 
   final Severity severity;
 
-  const Code(this.name, this.template,
-      {int index, this.analyzerCodes, this.severity: Severity.error})
-      : this.index = index ?? -1;
+  const Code(this.name,
+      {this.index: -1, this.analyzerCodes, this.severity: Severity.error});
 
   String toString() => name;
 }
@@ -44,11 +41,12 @@
 
   final String message;
 
-  final String tip;
+  final String? tip;
 
   final Map<String, dynamic> arguments;
 
-  const Message(this.code, {this.message, this.tip, this.arguments});
+  const Message(this.code,
+      {required this.message, this.tip, this.arguments = const {}});
 
   LocatedMessage withLocation(Uri uri, int charOffset, int length) {
     return new LocatedMessage(uri, charOffset, length, this);
@@ -66,15 +64,15 @@
 class MessageCode extends Code<Null> implements Message {
   final String message;
 
-  final String tip;
+  final String? tip;
 
   const MessageCode(String name,
-      {int index,
-      List<String> analyzerCodes,
+      {int index: -1,
+      List<String>? analyzerCodes,
       Severity severity: Severity.error,
-      this.message,
+      required this.message,
       this.tip})
-      : super(name, null,
+      : super(name,
             index: index, analyzerCodes: analyzerCodes, severity: severity);
 
   Map<String, dynamic> get arguments => const <String, dynamic>{};
@@ -94,15 +92,18 @@
 class Template<T> {
   final String messageTemplate;
 
-  final String tipTemplate;
+  final String? tipTemplate;
 
   final T withArguments;
 
-  const Template({this.messageTemplate, this.tipTemplate, this.withArguments});
+  const Template(
+      {required this.messageTemplate,
+      this.tipTemplate,
+      required this.withArguments});
 }
 
 class LocatedMessage implements Comparable<LocatedMessage> {
-  final Uri uri;
+  final Uri? uri;
 
   final int charOffset;
 
@@ -117,7 +118,7 @@
 
   String get message => messageObject.message;
 
-  String get tip => messageObject.tip;
+  String? get tip => messageObject.tip;
 
   Map<String, dynamic> get arguments => messageObject.arguments;
 
@@ -132,7 +133,7 @@
 
   FormattedMessage withFormatting(String formatted, int line, int column,
       Severity severity, List<FormattedMessage> relatedInformation,
-      {List<Uri> involvedFiles}) {
+      {List<Uri>? involvedFiles}) {
     return new FormattedMessage(
         this, formatted, line, column, severity, relatedInformation,
         involvedFiles: involvedFiles);
@@ -173,9 +174,9 @@
   @override
   final Severity severity;
 
-  final List<FormattedMessage> relatedInformation;
+  final List<FormattedMessage>? relatedInformation;
 
-  final List<Uri> involvedFiles;
+  final List<Uri>? involvedFiles;
 
   const FormattedMessage(this.locatedMessage, this.formatted, this.line,
       this.column, this.severity, this.relatedInformation,
@@ -187,11 +188,11 @@
 
   String get message => locatedMessage.message;
 
-  String get tip => locatedMessage.tip;
+  String? get tip => locatedMessage.tip;
 
   Map<String, dynamic> get arguments => locatedMessage.arguments;
 
-  Uri get uri => locatedMessage.uri;
+  Uri? get uri => locatedMessage.uri;
 
   int get charOffset => locatedMessage.charOffset;
 
@@ -201,7 +202,7 @@
   Iterable<String> get ansiFormatted sync* {
     yield formatted;
     if (relatedInformation != null) {
-      for (FormattedMessage m in relatedInformation) {
+      for (FormattedMessage m in relatedInformation!) {
         yield m.formatted;
       }
     }
@@ -213,14 +214,14 @@
     return ansiFormatted;
   }
 
-  Map<String, Object> toJson() {
+  Map<String, Object?> toJson() {
     // This should be kept in sync with package:kernel/problems.md
-    return <String, Object>{
+    return <String, Object?>{
       "ansiFormatted": ansiFormatted.toList(),
       "plainTextFormatted": plainTextFormatted.toList(),
       "severity": severity.index,
       "uri": uri?.toString(),
-      "involvedFiles": involvedFiles?.map((u) => u.toString())?.toList(),
+      "involvedFiles": involvedFiles?.map((u) => u.toString()).toList(),
       "codeName": code.name,
     };
   }
@@ -241,9 +242,9 @@
   @override
   final Severity severity;
 
-  final Uri uri;
+  final Uri? uri;
 
-  final List<Uri> involvedFiles;
+  final List<Uri>? involvedFiles;
 
   final String codeName;
 
@@ -253,30 +254,31 @@
   factory DiagnosticMessageFromJson.fromJson(String jsonString) {
     Map<String, Object> decoded = json.decode(jsonString);
     List<String> ansiFormatted =
-        new List<String>.from(decoded["ansiFormatted"]);
+        new List<String>.from(_asListOfString(decoded["ansiFormatted"]));
     List<String> plainTextFormatted =
-        new List<String>.from(decoded["plainTextFormatted"]);
-    Severity severity = Severity.values[decoded["severity"]];
-    Uri uri = decoded["uri"] == null ? null : Uri.parse(decoded["uri"]);
-    List<Uri> involvedFiles = decoded["involvedFiles"] == null
+        _asListOfString(decoded["plainTextFormatted"]);
+    Severity severity = Severity.values[decoded["severity"] as int];
+    Uri? uri =
+        decoded["uri"] == null ? null : Uri.parse(decoded["uri"] as String);
+    List<Uri>? involvedFiles = decoded["involvedFiles"] == null
         ? null
-        : new List<String>.from(decoded["involvedFiles"])
+        : _asListOfString(decoded["involvedFiles"])
             .map((e) => Uri.parse(e))
             .toList();
-    String codeName = decoded["codeName"];
+    String codeName = decoded["codeName"] as String;
 
     return new DiagnosticMessageFromJson(ansiFormatted, plainTextFormatted,
         severity, uri, involvedFiles, codeName);
   }
 
-  Map<String, Object> toJson() {
+  Map<String, Object?> toJson() {
     // This should be kept in sync with package:kernel/problems.md
-    return <String, Object>{
+    return <String, Object?>{
       "ansiFormatted": ansiFormatted.toList(),
       "plainTextFormatted": plainTextFormatted.toList(),
       "severity": severity.index,
       "uri": uri?.toString(),
-      "involvedFiles": involvedFiles?.map((u) => u.toString())?.toList(),
+      "involvedFiles": involvedFiles?.map((u) => u.toString()).toList(),
       "codeName": codeName,
     };
   }
@@ -285,9 +287,13 @@
     JsonEncoder encoder = new JsonEncoder.withIndent("  ");
     return encoder.convert(this);
   }
+
+  static List<String> _asListOfString(Object? value) {
+    return (value as List<dynamic>).cast<String>();
+  }
 }
 
-String relativizeUri(Uri uri) {
+String? relativizeUri(Uri? uri) {
   // We have this method here for two reasons:
   //
   // 1. It allows us to implement #uri message argument without using it
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 c3e3577..d3dd826 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -21,8 +21,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeAbstractClassInstantiation =
-    const Code<Message Function(String name)>(
-        "AbstractClassInstantiation", templateAbstractClassInstantiation,
+    const Code<Message Function(String name)>("AbstractClassInstantiation",
         analyzerCodes: <String>["NEW_WITH_ABSTRACT_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -117,7 +116,6 @@
     codeAbstractRedirectedClassInstantiation =
     const Code<Message Function(String name)>(
         "AbstractRedirectedClassInstantiation",
-        templateAbstractRedirectedClassInstantiation,
         analyzerCodes: <String>["FACTORY_REDIRECTS_TO_ABSTRACT_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -150,7 +148,6 @@
 const Code<Message Function(String name)> codeAccessError =
     const Code<Message Function(String name)>(
   "AccessError",
-  templateAccessError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -242,8 +239,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(int codePoint)> codeAsciiControlCharacter =
-    const Code<Message Function(int codePoint)>(
-        "AsciiControlCharacter", templateAsciiControlCharacter,
+    const Code<Message Function(int codePoint)>("AsciiControlCharacter",
         analyzerCodes: <String>["ILLEGAL_CHARACTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -328,7 +324,7 @@
 const Code<Message Function(String string, String string2)>
     codeBinaryOperatorWrittenOut =
     const Code<Message Function(String string, String string2)>(
-        "BinaryOperatorWrittenOut", templateBinaryOperatorWrittenOut,
+        "BinaryOperatorWrittenOut",
         index: 112);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -361,7 +357,6 @@
     codeBoundIssueViaCycleNonSimplicity =
     const Code<Message Function(String name, String name2)>(
         "BoundIssueViaCycleNonSimplicity",
-        templateBoundIssueViaCycleNonSimplicity,
         analyzerCodes: <String>["NOT_INSTANTIATED_BOUND"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -392,7 +387,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeBoundIssueViaLoopNonSimplicity =
     const Code<Message Function(String name)>("BoundIssueViaLoopNonSimplicity",
-        templateBoundIssueViaLoopNonSimplicity,
         analyzerCodes: <String>["NOT_INSTANTIATED_BOUND"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -420,7 +414,6 @@
     codeBoundIssueViaRawTypeWithNonSimpleBounds =
     const Code<Message Function(String name)>(
         "BoundIssueViaRawTypeWithNonSimpleBounds",
-        templateBoundIssueViaRawTypeWithNonSimpleBounds,
         analyzerCodes: <String>["NOT_INSTANTIATED_BOUND"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -454,8 +447,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeBreakTargetOutsideFunction =
-    const Code<Message Function(String name)>(
-        "BreakTargetOutsideFunction", templateBreakTargetOutsideFunction,
+    const Code<Message Function(String name)>("BreakTargetOutsideFunction",
         analyzerCodes: <String>["LABEL_IN_OUTER_SCOPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -476,8 +468,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeBuiltInIdentifierAsType =
-    const Code<Message Function(Token token)>(
-        "BuiltInIdentifierAsType", templateBuiltInIdentifierAsType,
+    const Code<Message Function(Token token)>("BuiltInIdentifierAsType",
         analyzerCodes: <String>["BUILT_IN_IDENTIFIER_AS_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -499,7 +490,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeBuiltInIdentifierInDeclaration =
     const Code<Message Function(Token token)>("BuiltInIdentifierInDeclaration",
-        templateBuiltInIdentifierInDeclaration,
         analyzerCodes: <String>["BUILT_IN_IDENTIFIER_IN_DECLARATION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -531,7 +521,6 @@
     codeCandidateFoundIsDefaultConstructor =
     const Code<Message Function(String name)>(
         "CandidateFoundIsDefaultConstructor",
-        templateCandidateFoundIsDefaultConstructor,
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -555,7 +544,6 @@
 const Code<Message Function(String name)> codeCannotAssignToConstVariable =
     const Code<Message Function(String name)>(
   "CannotAssignToConstVariable",
-  templateCannotAssignToConstVariable,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -587,7 +575,6 @@
 const Code<Message Function(String name)> codeCannotAssignToFinalVariable =
     const Code<Message Function(String name)>(
   "CannotAssignToFinalVariable",
-  templateCannotAssignToFinalVariable,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -640,7 +627,6 @@
 const Code<Message Function(String string)> codeCannotReadSdkSpecification =
     const Code<Message Function(String string)>(
   "CannotReadSdkSpecification",
-  templateCannotReadSdkSpecification,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -708,7 +694,6 @@
     codeCantInferReturnTypeDueToNoCombinedSignature =
     const Code<Message Function(String name)>(
         "CantInferReturnTypeDueToNoCombinedSignature",
-        templateCantInferReturnTypeDueToNoCombinedSignature,
         analyzerCodes: <String>[
       "COMPILE_TIME_ERROR.NO_COMBINED_SUPER_SIGNATURE"
     ]);
@@ -737,8 +722,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string)> codeCantInferTypeDueToCircularity =
-    const Code<Message Function(String string)>(
-        "CantInferTypeDueToCircularity", templateCantInferTypeDueToCircularity,
+    const Code<Message Function(String string)>("CantInferTypeDueToCircularity",
         analyzerCodes: <String>["RECURSIVE_COMPILE_TIME_CONSTANT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -767,7 +751,6 @@
     codeCantInferTypeDueToNoCombinedSignature =
     const Code<Message Function(String name)>(
         "CantInferTypeDueToNoCombinedSignature",
-        templateCantInferTypeDueToNoCombinedSignature,
         analyzerCodes: <String>[
       "COMPILE_TIME_ERROR.NO_COMBINED_SUPER_SIGNATURE"
     ]);
@@ -799,7 +782,6 @@
     codeCantInferTypesDueToNoCombinedSignature =
     const Code<Message Function(String name)>(
         "CantInferTypesDueToNoCombinedSignature",
-        templateCantInferTypesDueToNoCombinedSignature,
         analyzerCodes: <String>[
       "COMPILE_TIME_ERROR.NO_COMBINED_SUPER_SIGNATURE"
     ]);
@@ -823,13 +805,12 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Uri uri_, String string)> codeCantReadFile =
-    const Code<Message Function(Uri uri_, String string)>(
-        "CantReadFile", templateCantReadFile,
+    const Code<Message Function(Uri uri_, String string)>("CantReadFile",
         analyzerCodes: <String>["URI_DOES_NOT_EXIST"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsCantReadFile(Uri uri_, String string) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   if (string.isEmpty) throw 'No string provided';
   return new Message(codeCantReadFile,
       message: """Error when reading '${uri}': ${string}""",
@@ -849,7 +830,6 @@
     codeCantUseControlFlowOrSpreadAsConstant =
     const Code<Message Function(Token token)>(
         "CantUseControlFlowOrSpreadAsConstant",
-        templateCantUseControlFlowOrSpreadAsConstant,
         analyzerCodes: <String>["NOT_CONSTANT_EXPRESSION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -876,7 +856,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeCantUseDeferredPrefixAsConstant =
     const Code<Message Function(Token token)>("CantUseDeferredPrefixAsConstant",
-        templateCantUseDeferredPrefixAsConstant,
         analyzerCodes: <String>["CONST_DEFERRED_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -953,8 +932,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeClassInNullAwareReceiver =
-    const Code<Message Function(String name)>(
-        "ClassInNullAwareReceiver", templateClassInNullAwareReceiver,
+    const Code<Message Function(String name)>("ClassInNullAwareReceiver",
         severity: Severity.warning);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -993,7 +971,7 @@
 const Code<Message Function(String name, String name2)>
     codeCombinedMemberSignatureFailed =
     const Code<Message Function(String name, String name2)>(
-        "CombinedMemberSignatureFailed", templateCombinedMemberSignatureFailed,
+        "CombinedMemberSignatureFailed",
         analyzerCodes: <String>["INCONSISTENT_INHERITANCE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1025,7 +1003,7 @@
 const Code<Message Function(String string, String string2)>
     codeConflictingModifiers =
     const Code<Message Function(String string, String string2)>(
-        "ConflictingModifiers", templateConflictingModifiers,
+        "ConflictingModifiers",
         index: 59);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1047,8 +1025,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeConflictsWithConstructor =
-    const Code<Message Function(String name)>(
-        "ConflictsWithConstructor", templateConflictsWithConstructor,
+    const Code<Message Function(String name)>("ConflictsWithConstructor",
         analyzerCodes: <String>["CONFLICTS_WITH_CONSTRUCTOR"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1070,7 +1047,6 @@
 const Code<Message Function(String name)> codeConflictsWithFactory =
     const Code<Message Function(String name)>(
   "ConflictsWithFactory",
-  templateConflictsWithFactory,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1090,8 +1066,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeConflictsWithMember =
-    const Code<Message Function(String name)>(
-        "ConflictsWithMember", templateConflictsWithMember,
+    const Code<Message Function(String name)>("ConflictsWithMember",
         analyzerCodes: <String>["CONFLICTS_WITH_MEMBER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1111,8 +1086,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeConflictsWithSetter =
-    const Code<Message Function(String name)>(
-        "ConflictsWithSetter", templateConflictsWithSetter,
+    const Code<Message Function(String name)>("ConflictsWithSetter",
         analyzerCodes: <String>["CONFLICTS_WITH_MEMBER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1133,8 +1107,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeConflictsWithTypeVariable =
-    const Code<Message Function(String name)>(
-        "ConflictsWithTypeVariable", templateConflictsWithTypeVariable,
+    const Code<Message Function(String name)>("ConflictsWithTypeVariable",
         analyzerCodes: <String>["CONFLICTING_TYPE_VARIABLE_AND_MEMBER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1276,14 +1249,14 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String nameOKEmpty)> codeConstEvalDeferredLibrary =
-    const Code<Message Function(String nameOKEmpty)>(
-        "ConstEvalDeferredLibrary", templateConstEvalDeferredLibrary,
+    const Code<Message Function(String nameOKEmpty)>("ConstEvalDeferredLibrary",
         analyzerCodes: <String>[
       "NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LIBRARY"
     ]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsConstEvalDeferredLibrary(String nameOKEmpty) {
+  // ignore: unnecessary_null_comparison
   if (nameOKEmpty == null || nameOKEmpty.isEmpty) nameOKEmpty = '(unnamed)';
   return new Message(codeConstEvalDeferredLibrary,
       message:
@@ -1325,12 +1298,12 @@
     codeConstEvalFailedAssertionWithMessage =
     const Code<Message Function(String stringOKEmpty)>(
         "ConstEvalFailedAssertionWithMessage",
-        templateConstEvalFailedAssertionWithMessage,
         analyzerCodes: <String>["CONST_EVAL_THROWS_EXCEPTION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsConstEvalFailedAssertionWithMessage(
     String stringOKEmpty) {
+  // ignore: unnecessary_null_comparison
   if (stringOKEmpty == null || stringOKEmpty.isEmpty) stringOKEmpty = '(empty)';
   return new Message(codeConstEvalFailedAssertionWithMessage,
       message: """This assertion failed with message: ${stringOKEmpty}""",
@@ -1350,11 +1323,11 @@
     codeConstEvalInvalidStaticInvocation =
     const Code<Message Function(String nameOKEmpty)>(
         "ConstEvalInvalidStaticInvocation",
-        templateConstEvalInvalidStaticInvocation,
         analyzerCodes: <String>["CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsConstEvalInvalidStaticInvocation(String nameOKEmpty) {
+  // ignore: unnecessary_null_comparison
   if (nameOKEmpty == null || nameOKEmpty.isEmpty) nameOKEmpty = '(unnamed)';
   return new Message(codeConstEvalInvalidStaticInvocation,
       message:
@@ -1379,7 +1352,6 @@
     codeConstEvalNegativeShift =
     const Code<Message Function(String string, String string2, String string3)>(
   "ConstEvalNegativeShift",
-  templateConstEvalNegativeShift,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1409,11 +1381,11 @@
     codeConstEvalNonConstantVariableGet =
     const Code<Message Function(String nameOKEmpty)>(
         "ConstEvalNonConstantVariableGet",
-        templateConstEvalNonConstantVariableGet,
         analyzerCodes: <String>["NON_CONSTANT_VALUE_IN_INITIALIZER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsConstEvalNonConstantVariableGet(String nameOKEmpty) {
+  // ignore: unnecessary_null_comparison
   if (nameOKEmpty == null || nameOKEmpty.isEmpty) nameOKEmpty = '(unnamed)';
   return new Message(codeConstEvalNonConstantVariableGet,
       message:
@@ -1482,7 +1454,6 @@
     codeConstEvalTruncateError =
     const Code<Message Function(String string, String string2)>(
   "ConstEvalTruncateError",
-  templateConstEvalTruncateError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1518,7 +1489,7 @@
 const Code<Message Function(String string, String string2)>
     codeConstEvalZeroDivisor =
     const Code<Message Function(String string, String string2)>(
-        "ConstEvalZeroDivisor", templateConstEvalZeroDivisor,
+        "ConstEvalZeroDivisor",
         analyzerCodes: <String>["CONST_EVAL_THROWS_IDBZE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1568,8 +1539,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeConstFieldWithoutInitializer =
-    const Code<Message Function(String name)>(
-        "ConstFieldWithoutInitializer", templateConstFieldWithoutInitializer,
+    const Code<Message Function(String name)>("ConstFieldWithoutInitializer",
         analyzerCodes: <String>["CONST_NOT_INITIALIZED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1628,7 +1598,6 @@
     codeConstructorInitializeSameInstanceVariableSeveralTimes =
     const Code<Message Function(String name)>(
         "ConstructorInitializeSameInstanceVariableSeveralTimes",
-        templateConstructorInitializeSameInstanceVariableSeveralTimes,
         analyzerCodes: <String>["FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1649,8 +1618,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeConstructorNotFound =
-    const Code<Message Function(String name)>(
-        "ConstructorNotFound", templateConstructorNotFound,
+    const Code<Message Function(String name)>("ConstructorNotFound",
         analyzerCodes: <String>["CONSTRUCTOR_NOT_FOUND"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1726,7 +1694,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeConstructorWithWrongNameContext =
     const Code<Message Function(String name)>("ConstructorWithWrongNameContext",
-        templateConstructorWithWrongNameContext,
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1768,8 +1735,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeContinueTargetOutsideFunction =
-    const Code<Message Function(String name)>(
-        "ContinueTargetOutsideFunction", templateContinueTargetOutsideFunction,
+    const Code<Message Function(String name)>("ContinueTargetOutsideFunction",
         analyzerCodes: <String>["LABEL_IN_OUTER_SCOPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1806,7 +1772,6 @@
     codeCouldNotParseUri =
     const Code<Message Function(String string, String string2)>(
   "CouldNotParseUri",
-  templateCouldNotParseUri,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1855,7 +1820,7 @@
 const Code<Message Function(String name, String string)>
     codeCycleInTypeVariables =
     const Code<Message Function(String name, String string)>(
-        "CycleInTypeVariables", templateCycleInTypeVariables,
+        "CycleInTypeVariables",
         analyzerCodes: <String>["TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1878,8 +1843,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeCyclicClassHierarchy =
-    const Code<Message Function(String name)>(
-        "CyclicClassHierarchy", templateCyclicClassHierarchy,
+    const Code<Message Function(String name)>("CyclicClassHierarchy",
         analyzerCodes: <String>["RECURSIVE_INTERFACE_INHERITANCE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1903,7 +1867,6 @@
     codeCyclicRedirectingFactoryConstructors =
     const Code<Message Function(String name)>(
         "CyclicRedirectingFactoryConstructors",
-        templateCyclicRedirectingFactoryConstructors,
         analyzerCodes: <String>["RECURSIVE_FACTORY_REDIRECT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1923,8 +1886,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeCyclicTypedef =
-    const Code<Message Function(String name)>(
-        "CyclicTypedef", templateCyclicTypedef,
+    const Code<Message Function(String name)>("CyclicTypedef",
         analyzerCodes: <String>["TYPE_ALIAS_CANNOT_REFERENCE_ITSELF"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1945,8 +1907,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name, String string)> codeDebugTrace =
-    const Code<Message Function(String name, String string)>(
-        "DebugTrace", templateDebugTrace,
+    const Code<Message Function(String name, String string)>("DebugTrace",
         severity: Severity.ignored);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2014,7 +1975,6 @@
     codeDefaultValueInRedirectingFactoryConstructor =
     const Code<Message Function(String name)>(
         "DefaultValueInRedirectingFactoryConstructor",
-        templateDefaultValueInRedirectingFactoryConstructor,
         analyzerCodes: <String>[
       "DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUCTOR"
     ]);
@@ -2056,7 +2016,6 @@
 const Code<Message Function(String name)> codeDeferredExtensionImport =
     const Code<Message Function(String name)>(
   "DeferredExtensionImport",
-  templateDeferredExtensionImport,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2082,8 +2041,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeDeferredPrefixDuplicated =
-    const Code<Message Function(String name)>(
-        "DeferredPrefixDuplicated", templateDeferredPrefixDuplicated,
+    const Code<Message Function(String name)>("DeferredPrefixDuplicated",
         analyzerCodes: <String>["SHARED_DEFERRED_PREFIX"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2105,8 +2063,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeDeferredPrefixDuplicatedCause =
-    const Code<Message Function(String name)>(
-        "DeferredPrefixDuplicatedCause", templateDeferredPrefixDuplicatedCause,
+    const Code<Message Function(String name)>("DeferredPrefixDuplicatedCause",
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2136,18 +2093,22 @@
         num _num3)> codeDillOutlineSummary = const Code<
     Message Function(int count, int count2, num _num1, num _num2, num _num3)>(
   "DillOutlineSummary",
-  templateDillOutlineSummary,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsDillOutlineSummary(
     int count, int count2, num _num1, num _num2, num _num3) {
+  // ignore: unnecessary_null_comparison
   if (count == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
   if (count2 == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
   if (_num1 == null) throw 'No number provided';
   String num1 = _num1.toStringAsFixed(3);
+  // ignore: unnecessary_null_comparison
   if (_num2 == null) throw 'No number provided';
   String num2 = _num2.toStringAsFixed(3).padLeft(12);
+  // ignore: unnecessary_null_comparison
   if (_num3 == null) throw 'No number provided';
   String num3 = _num3.toStringAsFixed(3).padLeft(12);
   return new Message(codeDillOutlineSummary,
@@ -2177,8 +2138,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeDirectCycleInTypeVariables =
-    const Code<Message Function(String name)>(
-        "DirectCycleInTypeVariables", templateDirectCycleInTypeVariables,
+    const Code<Message Function(String name)>("DirectCycleInTypeVariables",
         analyzerCodes: <String>["TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2225,7 +2185,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeDuplicateLabelInSwitchStatement =
     const Code<Message Function(String name)>("DuplicateLabelInSwitchStatement",
-        templateDuplicateLabelInSwitchStatement,
         index: 72);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2256,8 +2215,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeDuplicatedDeclaration =
-    const Code<Message Function(String name)>(
-        "DuplicatedDeclaration", templateDuplicatedDeclaration,
+    const Code<Message Function(String name)>("DuplicatedDeclaration",
         analyzerCodes: <String>["DUPLICATE_DEFINITION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2278,8 +2236,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeDuplicatedDeclarationCause =
-    const Code<Message Function(String name)>(
-        "DuplicatedDeclarationCause", templateDuplicatedDeclarationCause,
+    const Code<Message Function(String name)>("DuplicatedDeclarationCause",
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2306,7 +2263,6 @@
     codeDuplicatedDeclarationSyntheticCause =
     const Code<Message Function(String name)>(
         "DuplicatedDeclarationSyntheticCause",
-        templateDuplicatedDeclarationSyntheticCause,
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2330,7 +2286,6 @@
 const Code<Message Function(String name)> codeDuplicatedDeclarationUse =
     const Code<Message Function(String name)>(
   "DuplicatedDeclarationUse",
-  templateDuplicatedDeclarationUse,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2354,15 +2309,15 @@
 const Code<Message Function(String name, Uri uri_, Uri uri2_)>
     codeDuplicatedExport =
     const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
-        "DuplicatedExport", templateDuplicatedExport,
+        "DuplicatedExport",
         analyzerCodes: <String>["AMBIGUOUS_EXPORT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsDuplicatedExport(String name, Uri uri_, Uri uri2_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
-  String uri2 = relativizeUri(uri2_);
+  String? uri = relativizeUri(uri_);
+  String? uri2 = relativizeUri(uri2_);
   return new Message(codeDuplicatedExport,
       message: """'${name}' is exported from both '${uri}' and '${uri2}'.""",
       arguments: {'name': name, 'uri': uri_, 'uri2': uri2_});
@@ -2381,15 +2336,14 @@
     codeDuplicatedExportInType =
     const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
   "DuplicatedExportInType",
-  templateDuplicatedExportInType,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsDuplicatedExportInType(String name, Uri uri_, Uri uri2_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
-  String uri2 = relativizeUri(uri2_);
+  String? uri = relativizeUri(uri_);
+  String? uri2 = relativizeUri(uri2_);
   return new Message(codeDuplicatedExportInType,
       message: """'${name}' is exported from both '${uri}' and '${uri2}'.""",
       arguments: {'name': name, 'uri': uri_, 'uri2': uri2_});
@@ -2407,15 +2361,15 @@
 const Code<Message Function(String name, Uri uri_, Uri uri2_)>
     codeDuplicatedImport =
     const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
-        "DuplicatedImport", templateDuplicatedImport,
+        "DuplicatedImport",
         severity: Severity.ignored);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsDuplicatedImport(String name, Uri uri_, Uri uri2_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
-  String uri2 = relativizeUri(uri2_);
+  String? uri = relativizeUri(uri_);
+  String? uri2 = relativizeUri(uri2_);
   return new Message(codeDuplicatedImport,
       message: """'${name}' is imported from both '${uri}' and '${uri2}'.""",
       arguments: {'name': name, 'uri': uri_, 'uri2': uri2_});
@@ -2433,15 +2387,15 @@
 const Code<Message Function(String name, Uri uri_, Uri uri2_)>
     codeDuplicatedImportInType =
     const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
-        "DuplicatedImportInType", templateDuplicatedImportInType,
+        "DuplicatedImportInType",
         analyzerCodes: <String>["AMBIGUOUS_IMPORT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsDuplicatedImportInType(String name, Uri uri_, Uri uri2_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
-  String uri2 = relativizeUri(uri2_);
+  String? uri = relativizeUri(uri_);
+  String? uri2 = relativizeUri(uri2_);
   return new Message(codeDuplicatedImportInType,
       message: """'${name}' is imported from both '${uri}' and '${uri2}'.""",
       arguments: {'name': name, 'uri': uri_, 'uri2': uri2_});
@@ -2457,9 +2411,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeDuplicatedModifier =
-    const Code<Message Function(Token token)>(
-        "DuplicatedModifier", templateDuplicatedModifier,
-        index: 70);
+    const Code<Message Function(Token token)>("DuplicatedModifier", index: 70);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsDuplicatedModifier(Token token) {
@@ -2482,8 +2434,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeDuplicatedNamePreviouslyUsed =
-    const Code<Message Function(String name)>(
-        "DuplicatedNamePreviouslyUsed", templateDuplicatedNamePreviouslyUsed,
+    const Code<Message Function(String name)>("DuplicatedNamePreviouslyUsed",
         analyzerCodes: <String>["REFERENCED_BEFORE_DECLARATION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2508,7 +2459,6 @@
     codeDuplicatedNamePreviouslyUsedCause =
     const Code<Message Function(String name)>(
         "DuplicatedNamePreviouslyUsedCause",
-        templateDuplicatedNamePreviouslyUsedCause,
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2527,8 +2477,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeDuplicatedNamedArgument =
-    const Code<Message Function(String name)>(
-        "DuplicatedNamedArgument", templateDuplicatedNamedArgument,
+    const Code<Message Function(String name)>("DuplicatedNamedArgument",
         analyzerCodes: <String>["DUPLICATE_NAMED_ARGUMENT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2548,8 +2497,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeDuplicatedParameterName =
-    const Code<Message Function(String name)>(
-        "DuplicatedParameterName", templateDuplicatedParameterName,
+    const Code<Message Function(String name)>("DuplicatedParameterName",
         analyzerCodes: <String>["DUPLICATE_DEFINITION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2570,8 +2518,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeDuplicatedParameterNameCause =
-    const Code<Message Function(String name)>(
-        "DuplicatedParameterNameCause", templateDuplicatedParameterNameCause,
+    const Code<Message Function(String name)>("DuplicatedParameterNameCause",
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2624,7 +2571,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeEnumConstantSameNameAsEnclosing =
     const Code<Message Function(String name)>("EnumConstantSameNameAsEnclosing",
-        templateEnumConstantSameNameAsEnclosing,
         analyzerCodes: <String>["ENUM_CONSTANT_WITH_ENUM_NAME"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2687,12 +2633,11 @@
 const Code<Message Function(Uri uri_, String string)> codeExceptionReadingFile =
     const Code<Message Function(Uri uri_, String string)>(
   "ExceptionReadingFile",
-  templateExceptionReadingFile,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsExceptionReadingFile(Uri uri_, String string) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   if (string.isEmpty) throw 'No string provided';
   return new Message(codeExceptionReadingFile,
       message: """Exception when reading '${uri}': ${string}""",
@@ -2707,8 +2652,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string)> codeExpectedAfterButGot =
-    const Code<Message Function(String string)>(
-        "ExpectedAfterButGot", templateExpectedAfterButGot,
+    const Code<Message Function(String string)>("ExpectedAfterButGot",
         analyzerCodes: <String>["EXPECTED_TOKEN"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2764,8 +2708,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string)> codeExpectedButGot =
-    const Code<Message Function(String string)>(
-        "ExpectedButGot", templateExpectedButGot,
+    const Code<Message Function(String string)>("ExpectedButGot",
         analyzerCodes: <String>["EXPECTED_TOKEN"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2784,8 +2727,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeExpectedClassMember =
-    const Code<Message Function(Token token)>(
-        "ExpectedClassMember", templateExpectedClassMember,
+    const Code<Message Function(Token token)>("ExpectedClassMember",
         analyzerCodes: <String>["EXPECTED_CLASS_MEMBER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2807,8 +2749,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string)> codeExpectedClassOrMixinBody =
-    const Code<Message Function(String string)>(
-        "ExpectedClassOrMixinBody", templateExpectedClassOrMixinBody,
+    const Code<Message Function(String string)>("ExpectedClassOrMixinBody",
         index: 8);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2828,8 +2769,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeExpectedDeclaration =
-    const Code<Message Function(Token token)>(
-        "ExpectedDeclaration", templateExpectedDeclaration,
+    const Code<Message Function(Token token)>("ExpectedDeclaration",
         analyzerCodes: <String>["EXPECTED_EXECUTABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2860,8 +2800,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeExpectedEnumBody =
-    const Code<Message Function(Token token)>(
-        "ExpectedEnumBody", templateExpectedEnumBody,
+    const Code<Message Function(Token token)>("ExpectedEnumBody",
         analyzerCodes: <String>["MISSING_ENUM_BODY"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2882,8 +2821,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeExpectedFunctionBody =
-    const Code<Message Function(Token token)>(
-        "ExpectedFunctionBody", templateExpectedFunctionBody,
+    const Code<Message Function(Token token)>("ExpectedFunctionBody",
         analyzerCodes: <String>["MISSING_FUNCTION_BODY"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2912,8 +2850,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeExpectedIdentifier =
-    const Code<Message Function(Token token)>(
-        "ExpectedIdentifier", templateExpectedIdentifier,
+    const Code<Message Function(Token token)>("ExpectedIdentifier",
         analyzerCodes: <String>["MISSING_IDENTIFIER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2941,7 +2878,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeExpectedIdentifierButGotKeyword =
     const Code<Message Function(Token token)>("ExpectedIdentifierButGotKeyword",
-        templateExpectedIdentifierButGotKeyword,
         index: 113);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2962,9 +2898,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string)> codeExpectedInstead =
-    const Code<Message Function(String string)>(
-        "ExpectedInstead", templateExpectedInstead,
-        index: 41);
+    const Code<Message Function(String string)>("ExpectedInstead", index: 41);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsExpectedInstead(String string) {
@@ -3015,8 +2949,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeExpectedString =
-    const Code<Message Function(Token token)>(
-        "ExpectedString", templateExpectedString,
+    const Code<Message Function(Token token)>("ExpectedString",
         analyzerCodes: <String>["EXPECTED_STRING_LITERAL"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3035,8 +2968,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string)> codeExpectedToken =
-    const Code<Message Function(String string)>(
-        "ExpectedToken", templateExpectedToken,
+    const Code<Message Function(String string)>("ExpectedToken",
         analyzerCodes: <String>["EXPECTED_TOKEN"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3055,8 +2987,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeExpectedType =
-    const Code<Message Function(Token token)>(
-        "ExpectedType", templateExpectedType,
+    const Code<Message Function(Token token)>("ExpectedType",
         analyzerCodes: <String>["EXPECTED_TYPE_NAME"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3088,8 +3019,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string)> codeExperimentDisabled =
-    const Code<Message Function(String string)>(
-        "ExperimentDisabled", templateExperimentDisabled,
+    const Code<Message Function(String string)>("ExperimentDisabled",
         analyzerCodes: <String>["ParserErrorCode.EXPERIMENT_NOT_ENABLED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3116,7 +3046,6 @@
     codeExperimentDisabledInvalidLanguageVersion =
     const Code<Message Function(String string2)>(
         "ExperimentDisabledInvalidLanguageVersion",
-        templateExperimentDisabledInvalidLanguageVersion,
         analyzerCodes: <String>["ParserErrorCode.EXPERIMENT_NOT_ENABLED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3145,7 +3074,7 @@
 const Code<Message Function(String string, String string2)>
     codeExperimentNotEnabled =
     const Code<Message Function(String string, String string2)>(
-        "ExperimentNotEnabled", templateExperimentNotEnabled,
+        "ExperimentNotEnabled",
         index: 48);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3189,7 +3118,6 @@
     codeExperimentNotEnabledNoFlagInvalidLanguageVersion =
     const Code<Message Function(String string2)>(
         "ExperimentNotEnabledNoFlagInvalidLanguageVersion",
-        templateExperimentNotEnabledNoFlagInvalidLanguageVersion,
         analyzerCodes: <String>["ParserErrorCode.EXPERIMENT_NOT_ENABLED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3249,7 +3177,6 @@
     codeExplicitExtensionTypeArgumentMismatch =
     const Code<Message Function(String name, int count)>(
   "ExplicitExtensionTypeArgumentMismatch",
-  templateExplicitExtensionTypeArgumentMismatch,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3257,6 +3184,7 @@
     String name, int count) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
+  // ignore: unnecessary_null_comparison
   if (count == null) throw 'No count provided';
   return new Message(codeExplicitExtensionTypeArgumentMismatch,
       message:
@@ -3285,15 +3213,15 @@
 const Code<Message Function(String name, Uri uri_, Uri uri2_)>
     codeExportHidesExport =
     const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
-        "ExportHidesExport", templateExportHidesExport,
+        "ExportHidesExport",
         severity: Severity.ignored);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsExportHidesExport(String name, Uri uri_, Uri uri2_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
-  String uri2 = relativizeUri(uri2_);
+  String? uri = relativizeUri(uri_);
+  String? uri2 = relativizeUri(uri2_);
   return new Message(codeExportHidesExport,
       message:
           """Export of '${name}' (from '${uri}') hides export from '${uri2}'.""",
@@ -3344,8 +3272,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeExtendingEnum =
-    const Code<Message Function(String name)>(
-        "ExtendingEnum", templateExtendingEnum,
+    const Code<Message Function(String name)>("ExtendingEnum",
         analyzerCodes: <String>["EXTENDS_ENUM"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3366,8 +3293,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeExtendingRestricted =
-    const Code<Message Function(String name)>(
-        "ExtendingRestricted", templateExtendingRestricted,
+    const Code<Message Function(String name)>("ExtendingRestricted",
         analyzerCodes: <String>["EXTENDS_DISALLOWED_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3447,7 +3373,6 @@
     codeExtensionMemberConflictsWithObjectMember =
     const Code<Message Function(String name)>(
   "ExtensionMemberConflictsWithObjectMember",
-  templateExtensionMemberConflictsWithObjectMember,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3601,9 +3526,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeExtraneousModifier =
-    const Code<Message Function(Token token)>(
-        "ExtraneousModifier", templateExtraneousModifier,
-        index: 77);
+    const Code<Message Function(Token token)>("ExtraneousModifier", index: 77);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsExtraneousModifier(Token token) {
@@ -3624,8 +3547,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeExtraneousModifierInExtension =
-    const Code<Message Function(Token token)>(
-        "ExtraneousModifierInExtension", templateExtraneousModifierInExtension,
+    const Code<Message Function(Token token)>("ExtraneousModifierInExtension",
         index: 98);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3666,7 +3588,6 @@
 const Code<Message Function(String name)> codeFastaCLIArgumentRequired =
     const Code<Message Function(String name)>(
   "FastaCLIArgumentRequired",
-  templateFastaCLIArgumentRequired,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3780,6 +3701,30 @@
   -h        Display this message (add -v for information about all options).""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(String name)> templateFfiEmptyStruct = const Template<
+        Message Function(String name)>(
+    messageTemplate:
+        r"""Struct '#name' is empty. Empty structs are undefined behavior.""",
+    withArguments: _withArgumentsFfiEmptyStruct);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)> codeFfiEmptyStruct =
+    const Code<Message Function(String name)>(
+  "FfiEmptyStruct",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFfiEmptyStruct(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeFfiEmptyStruct,
+      message:
+          """Struct '${name}' is empty. Empty structs are undefined behavior.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeFfiExceptionalReturnNull = messageFfiExceptionalReturnNull;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3808,7 +3753,6 @@
     codeFfiExtendsOrImplementsSealedClass =
     const Code<Message Function(String name)>(
   "FfiExtendsOrImplementsSealedClass",
-  templateFfiExtendsOrImplementsSealedClass,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3832,7 +3776,6 @@
 const Code<Message Function(String name)> codeFfiFieldAnnotation =
     const Code<Message Function(String name)>(
   "FfiFieldAnnotation",
-  templateFfiFieldAnnotation,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3857,7 +3800,6 @@
 const Code<Message Function(String name)> codeFfiFieldInitializer =
     const Code<Message Function(String name)>(
   "FfiFieldInitializer",
-  templateFfiFieldInitializer,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3884,7 +3826,6 @@
 const Code<Message Function(String name)> codeFfiFieldNoAnnotation =
     const Code<Message Function(String name)>(
   "FfiFieldNoAnnotation",
-  templateFfiFieldNoAnnotation,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3909,7 +3850,6 @@
 const Code<Message Function(String name)> codeFfiNotStatic =
     const Code<Message Function(String name)>(
   "FfiNotStatic",
-  templateFfiNotStatic,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3932,7 +3872,6 @@
 const Code<Message Function(String name)> codeFfiStructGeneric =
     const Code<Message Function(String name)>(
   "FfiStructGeneric",
-  templateFfiStructGeneric,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3959,7 +3898,6 @@
     codeFieldAlreadyInitializedAtDeclaration =
     const Code<Message Function(String name)>(
         "FieldAlreadyInitializedAtDeclaration",
-        templateFieldAlreadyInitializedAtDeclaration,
         analyzerCodes: <String>[
       "FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION"
     ]);
@@ -3986,7 +3924,6 @@
     codeFieldAlreadyInitializedAtDeclarationCause =
     const Code<Message Function(String name)>(
         "FieldAlreadyInitializedAtDeclarationCause",
-        templateFieldAlreadyInitializedAtDeclarationCause,
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4067,8 +4004,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeFinalFieldNotInitialized =
-    const Code<Message Function(String name)>(
-        "FinalFieldNotInitialized", templateFinalFieldNotInitialized,
+    const Code<Message Function(String name)>("FinalFieldNotInitialized",
         analyzerCodes: <String>["FINAL_NOT_INITIALIZED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4099,7 +4035,6 @@
     codeFinalFieldNotInitializedByConstructor =
     const Code<Message Function(String name)>(
         "FinalFieldNotInitializedByConstructor",
-        templateFinalFieldNotInitializedByConstructor,
         analyzerCodes: <String>["FINAL_NOT_INITIALIZED_CONSTRUCTOR_1"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4127,8 +4062,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeFinalFieldWithoutInitializer =
-    const Code<Message Function(String name)>(
-        "FinalFieldWithoutInitializer", templateFinalFieldWithoutInitializer,
+    const Code<Message Function(String name)>("FinalFieldWithoutInitializer",
         analyzerCodes: <String>["FINAL_NOT_INITIALIZED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4153,8 +4087,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeFinalNotAssignedError =
-    const Code<Message Function(String name)>(
-        "FinalNotAssignedError", templateFinalNotAssignedError,
+    const Code<Message Function(String name)>("FinalNotAssignedError",
         analyzerCodes: <String>["READ_POTENTIALLY_UNASSIGNED_FINAL"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4179,8 +4112,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeFinalPossiblyAssignedError =
-    const Code<Message Function(String name)>(
-        "FinalPossiblyAssignedError", templateFinalPossiblyAssignedError,
+    const Code<Message Function(String name)>("FinalPossiblyAssignedError",
         analyzerCodes: <String>["ASSIGNMENT_TO_FINAL_LOCAL"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4293,8 +4225,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeGetterNotFound =
-    const Code<Message Function(String name)>(
-        "GetterNotFound", templateGetterNotFound,
+    const Code<Message Function(String name)>("GetterNotFound",
         analyzerCodes: <String>["UNDEFINED_GETTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4364,8 +4295,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeIllegalMixin =
-    const Code<Message Function(String name)>(
-        "IllegalMixin", templateIllegalMixin,
+    const Code<Message Function(String name)>("IllegalMixin",
         analyzerCodes: <String>["ILLEGAL_MIXIN"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4387,8 +4317,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeIllegalMixinDueToConstructors =
-    const Code<Message Function(String name)>(
-        "IllegalMixinDueToConstructors", templateIllegalMixinDueToConstructors,
+    const Code<Message Function(String name)>("IllegalMixinDueToConstructors",
         analyzerCodes: <String>["MIXIN_DECLARES_CONSTRUCTOR"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4414,7 +4343,6 @@
     codeIllegalMixinDueToConstructorsCause =
     const Code<Message Function(String name)>(
         "IllegalMixinDueToConstructorsCause",
-        templateIllegalMixinDueToConstructorsCause,
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4512,14 +4440,14 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name, int count)> codeImplementsRepeated =
-    const Code<Message Function(String name, int count)>(
-        "ImplementsRepeated", templateImplementsRepeated,
+    const Code<Message Function(String name, int count)>("ImplementsRepeated",
         analyzerCodes: <String>["IMPLEMENTS_REPEATED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsImplementsRepeated(String name, int count) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
+  // ignore: unnecessary_null_comparison
   if (count == null) throw 'No count provided';
   return new Message(codeImplementsRepeated,
       message: """'${name}' can only be implemented once.""",
@@ -4540,8 +4468,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeImplementsSuperClass =
-    const Code<Message Function(String name)>(
-        "ImplementsSuperClass", templateImplementsSuperClass,
+    const Code<Message Function(String name)>("ImplementsSuperClass",
         analyzerCodes: <String>["IMPLEMENTS_SUPER_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4579,7 +4506,6 @@
     codeImplicitMixinOverride =
     const Code<Message Function(String name, String name2, String name3)>(
   "ImplicitMixinOverride",
-  templateImplicitMixinOverride,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4618,15 +4544,15 @@
 const Code<Message Function(String name, Uri uri_, Uri uri2_)>
     codeImportHidesImport =
     const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
-        "ImportHidesImport", templateImportHidesImport,
+        "ImportHidesImport",
         severity: Severity.ignored);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsImportHidesImport(String name, Uri uri_, Uri uri2_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
-  String uri2 = relativizeUri(uri2_);
+  String? uri = relativizeUri(uri_);
+  String? uri2 = relativizeUri(uri2_);
   return new Message(codeImportHidesImport,
       message:
           """Import of '${name}' (from '${uri}') hides import from '${uri2}'.""",
@@ -4658,7 +4584,6 @@
     codeIncrementalCompilerIllegalParameter =
     const Code<Message Function(String string)>(
   "IncrementalCompilerIllegalParameter",
-  templateIncrementalCompilerIllegalParameter,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4683,7 +4608,6 @@
     codeIncrementalCompilerIllegalTypeParameter =
     const Code<Message Function(String string)>(
   "IncrementalCompilerIllegalTypeParameter",
-  templateIncrementalCompilerIllegalTypeParameter,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4703,13 +4627,12 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Uri uri_)> codeInferredPackageUri =
-    const Code<Message Function(Uri uri_)>(
-        "InferredPackageUri", templateInferredPackageUri,
+    const Code<Message Function(Uri uri_)>("InferredPackageUri",
         severity: Severity.warning);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsInferredPackageUri(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeInferredPackageUri,
       message: """Interpreting this as package URI, '${uri}'.""",
       arguments: {'uri': uri_});
@@ -4764,14 +4687,13 @@
     codeInitializeFromDillNotSelfContained =
     const Code<Message Function(String string, Uri uri_)>(
         "InitializeFromDillNotSelfContained",
-        templateInitializeFromDillNotSelfContained,
         severity: Severity.warning);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsInitializeFromDillNotSelfContained(
     String string, Uri uri_) {
   if (string.isEmpty) throw 'No string provided';
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeInitializeFromDillNotSelfContained,
       message:
           """Tried to initialize from a previous compilation (${string}), but the file was not self-contained. This might be a bug.
@@ -4797,7 +4719,6 @@
     codeInitializeFromDillNotSelfContainedNoDump =
     const Code<Message Function(String string)>(
         "InitializeFromDillNotSelfContainedNoDump",
-        templateInitializeFromDillNotSelfContainedNoDump,
         severity: Severity.warning);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4840,7 +4761,6 @@
             Message Function(
                 String string, String string2, String string3, Uri uri_)>(
         "InitializeFromDillUnknownProblem",
-        templateInitializeFromDillUnknownProblem,
         severity: Severity.warning);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4849,7 +4769,7 @@
   if (string.isEmpty) throw 'No string provided';
   if (string2.isEmpty) throw 'No string provided';
   if (string3.isEmpty) throw 'No string provided';
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeInitializeFromDillUnknownProblem,
       message:
           """Tried to initialize from a previous compilation (${string}), but couldn't.
@@ -4886,7 +4806,6 @@
     codeInitializeFromDillUnknownProblemNoDump =
     const Code<Message Function(String string, String string2, String string3)>(
         "InitializeFromDillUnknownProblemNoDump",
-        templateInitializeFromDillUnknownProblemNoDump,
         severity: Severity.warning);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4927,8 +4846,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeInitializerForStaticField =
-    const Code<Message Function(String name)>(
-        "InitializerForStaticField", templateInitializerForStaticField,
+    const Code<Message Function(String name)>("InitializerForStaticField",
         analyzerCodes: <String>["INITIALIZER_FOR_STATIC_FIELD"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4960,12 +4878,11 @@
 const Code<Message Function(Uri uri_)> codeInputFileNotFound =
     const Code<Message Function(Uri uri_)>(
   "InputFileNotFound",
-  templateInputFileNotFound,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsInputFileNotFound(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeInputFileNotFound,
       message: """Input file not found: ${uri}.""", arguments: {'uri': uri_});
 }
@@ -4984,8 +4901,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string)> codeIntegerLiteralIsOutOfRange =
-    const Code<Message Function(String string)>(
-        "IntegerLiteralIsOutOfRange", templateIntegerLiteralIsOutOfRange,
+    const Code<Message Function(String string)>("IntegerLiteralIsOutOfRange",
         analyzerCodes: <String>["INTEGER_LITERAL_OUT_OF_RANGE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5014,7 +4930,6 @@
 const Code<Message Function(String name, String name2)> codeInterfaceCheck =
     const Code<Message Function(String name, String name2)>(
   "InterfaceCheck",
-  templateInterfaceCheck,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5061,7 +4976,6 @@
     codeInternalProblemConstructorNotFound =
     const Code<Message Function(String name, Uri uri_)>(
         "InternalProblemConstructorNotFound",
-        templateInternalProblemConstructorNotFound,
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5069,7 +4983,7 @@
     String name, Uri uri_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeInternalProblemConstructorNotFound,
       message: """No constructor named '${name}' in '${uri}'.""",
       arguments: {'name': name, 'uri': uri_});
@@ -5087,7 +5001,6 @@
 const Code<Message Function(String string)> codeInternalProblemContextSeverity =
     const Code<Message Function(String string)>(
         "InternalProblemContextSeverity",
-        templateInternalProblemContextSeverity,
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5109,7 +5022,7 @@
 const Code<Message Function(String name, String string)>
     codeInternalProblemDebugAbort =
     const Code<Message Function(String name, String string)>(
-        "InternalProblemDebugAbort", templateInternalProblemDebugAbort,
+        "InternalProblemDebugAbort",
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5163,8 +5076,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeInternalProblemNotFound =
-    const Code<Message Function(String name)>(
-        "InternalProblemNotFound", templateInternalProblemNotFound,
+    const Code<Message Function(String name)>("InternalProblemNotFound",
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5186,7 +5098,7 @@
 const Code<Message Function(String name, String name2)>
     codeInternalProblemNotFoundIn =
     const Code<Message Function(String name, String name2)>(
-        "InternalProblemNotFoundIn", templateInternalProblemNotFoundIn,
+        "InternalProblemNotFoundIn",
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5222,7 +5134,6 @@
     codeInternalProblemPrivateConstructorAccess =
     const Code<Message Function(String name)>(
         "InternalProblemPrivateConstructorAccess",
-        templateInternalProblemPrivateConstructorAccess,
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5256,7 +5167,7 @@
 const Code<Message Function(String name, String string)>
     codeInternalProblemStackNotEmpty =
     const Code<Message Function(String name, String string)>(
-        "InternalProblemStackNotEmpty", templateInternalProblemStackNotEmpty,
+        "InternalProblemStackNotEmpty",
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5280,7 +5191,7 @@
 const Code<Message Function(String string, String string2)>
     codeInternalProblemUnexpected =
     const Code<Message Function(String string, String string2)>(
-        "InternalProblemUnexpected", templateInternalProblemUnexpected,
+        "InternalProblemUnexpected",
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5308,7 +5219,6 @@
     codeInternalProblemUnfinishedTypeVariable =
     const Code<Message Function(String name, Uri uri_)>(
         "InternalProblemUnfinishedTypeVariable",
-        templateInternalProblemUnfinishedTypeVariable,
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5316,7 +5226,7 @@
     String name, Uri uri_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeInternalProblemUnfinishedTypeVariable,
       message:
           """Unfinished type variable '${name}' found in non-source library '${uri}'.""",
@@ -5334,7 +5244,7 @@
 const Code<Message Function(String string, String string2)>
     codeInternalProblemUnhandled =
     const Code<Message Function(String string, String string2)>(
-        "InternalProblemUnhandled", templateInternalProblemUnhandled,
+        "InternalProblemUnhandled",
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5355,8 +5265,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string)> codeInternalProblemUnimplemented =
-    const Code<Message Function(String string)>(
-        "InternalProblemUnimplemented", templateInternalProblemUnimplemented,
+    const Code<Message Function(String string)>("InternalProblemUnimplemented",
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5375,8 +5284,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeInternalProblemUnsupported =
-    const Code<Message Function(String name)>(
-        "InternalProblemUnsupported", templateInternalProblemUnsupported,
+    const Code<Message Function(String name)>("InternalProblemUnsupported",
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5398,12 +5306,11 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Uri uri_)> codeInternalProblemUriMissingScheme =
     const Code<Message Function(Uri uri_)>("InternalProblemUriMissingScheme",
-        templateInternalProblemUriMissingScheme,
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsInternalProblemUriMissingScheme(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeInternalProblemUriMissingScheme,
       message: """The URI '${uri}' has no scheme.""", arguments: {'uri': uri_});
 }
@@ -5420,7 +5327,6 @@
     codeInternalProblemVerificationError =
     const Code<Message Function(String string)>(
         "InternalProblemVerificationError",
-        templateInternalProblemVerificationError,
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5460,7 +5366,6 @@
 const Code<Message Function(String name)> codeInvalidBreakTarget =
     const Code<Message Function(String name)>(
   "InvalidBreakTarget",
-  templateInvalidBreakTarget,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5500,7 +5405,6 @@
 const Code<Message Function(String name)> codeInvalidContinueTarget =
     const Code<Message Function(String name)>(
   "InvalidContinueTarget",
-  templateInvalidContinueTarget,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5523,7 +5427,6 @@
     codeInvalidGetterSetterTypeFieldContext =
     const Code<Message Function(String name)>(
         "InvalidGetterSetterTypeFieldContext",
-        templateInvalidGetterSetterTypeFieldContext,
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5547,7 +5450,6 @@
     codeInvalidGetterSetterTypeGetterContext =
     const Code<Message Function(String name)>(
         "InvalidGetterSetterTypeGetterContext",
-        templateInvalidGetterSetterTypeGetterContext,
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5571,7 +5473,6 @@
     codeInvalidGetterSetterTypeSetterContext =
     const Code<Message Function(String name)>(
         "InvalidGetterSetterTypeSetterContext",
-        templateInvalidGetterSetterTypeSetterContext,
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5633,9 +5534,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeInvalidOperator =
-    const Code<Message Function(Token token)>(
-        "InvalidOperator", templateInvalidOperator,
-        index: 39);
+    const Code<Message Function(Token token)>("InvalidOperator", index: 39);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsInvalidOperator(Token token) {
@@ -5656,12 +5555,11 @@
 const Code<Message Function(Uri uri_, String string)> codeInvalidPackageUri =
     const Code<Message Function(Uri uri_, String string)>(
   "InvalidPackageUri",
-  templateInvalidPackageUri,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsInvalidPackageUri(Uri uri_, String string) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   if (string.isEmpty) throw 'No string provided';
   return new Message(codeInvalidPackageUri,
       message: """Invalid package URI '${uri}':
@@ -5716,7 +5614,6 @@
     codeInvalidTypeVariableInSupertype =
     const Code<Message Function(String name, String string2, String name2)>(
   "InvalidTypeVariableInSupertype",
-  templateInvalidTypeVariableInSupertype,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5753,7 +5650,6 @@
         Message Function(
             String string, String name, String string2, String name2)>(
   "InvalidTypeVariableInSupertypeWithVariance",
-  templateInvalidTypeVariableInSupertypeWithVariance,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5793,7 +5689,6 @@
     codeInvalidTypeVariableVariancePosition =
     const Code<Message Function(String string, String name, String string2)>(
   "InvalidTypeVariableVariancePosition",
-  templateInvalidTypeVariableVariancePosition,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5823,7 +5718,6 @@
     codeInvalidTypeVariableVariancePositionInReturnType =
     const Code<Message Function(String string, String name, String string2)>(
   "InvalidTypeVariableVariancePositionInReturnType",
-  templateInvalidTypeVariableVariancePositionInReturnType,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5879,8 +5773,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeInvokeNonFunction =
-    const Code<Message Function(String name)>(
-        "InvokeNonFunction", templateInvokeNonFunction,
+    const Code<Message Function(String name)>("InvokeNonFunction",
         analyzerCodes: <String>["INVOCATION_OF_NON_FUNCTION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5921,7 +5814,6 @@
     codeJsInteropDartClassExtendsJSClass =
     const Code<Message Function(String name, String name2)>(
   "JsInteropDartClassExtendsJSClass",
-  templateJsInteropDartClassExtendsJSClass,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -5989,7 +5881,6 @@
     codeJsInteropJSClassExtendsDartClass =
     const Code<Message Function(String name, String name2)>(
   "JsInteropJSClassExtendsDartClass",
-  templateJsInteropJSClassExtendsDartClass,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6050,8 +5941,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeLabelNotFound =
-    const Code<Message Function(String name)>(
-        "LabelNotFound", templateLabelNotFound,
+    const Code<Message Function(String name)>("LabelNotFound",
         analyzerCodes: <String>["LABEL_UNDEFINED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6140,12 +6030,13 @@
 const Code<Message Function(int count, int count2)> codeLanguageVersionTooHigh =
     const Code<Message Function(int count, int count2)>(
   "LanguageVersionTooHigh",
-  templateLanguageVersionTooHigh,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsLanguageVersionTooHigh(int count, int count2) {
+  // ignore: unnecessary_null_comparison
   if (count == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
   if (count2 == null) throw 'No count provided';
   return new Message(codeLanguageVersionTooHigh,
       message:
@@ -6165,7 +6056,6 @@
 const Code<Message Function(String name)> codeLateDefinitelyAssignedError =
     const Code<Message Function(String name)>(
   "LateDefinitelyAssignedError",
-  templateLateDefinitelyAssignedError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6191,7 +6081,6 @@
 const Code<Message Function(String name)> codeLateDefinitelyUnassignedError =
     const Code<Message Function(String name)>(
   "LateDefinitelyUnassignedError",
-  templateLateDefinitelyUnassignedError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6236,13 +6125,12 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Uri uri_)> codeLoadLibraryHidesMember =
-    const Code<Message Function(Uri uri_)>(
-        "LoadLibraryHidesMember", templateLoadLibraryHidesMember,
+    const Code<Message Function(Uri uri_)>("LoadLibraryHidesMember",
         severity: Severity.ignored);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsLoadLibraryHidesMember(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeLoadLibraryHidesMember,
       message:
           """The library '${uri}' defines a top-level member named 'loadLibrary'. This member is hidden by the special member 'loadLibrary' that the language adds to support deferred loading.""",
@@ -6272,14 +6160,14 @@
 const Code<Message Function(String name, Uri uri_)>
     codeLocalDefinitionHidesExport =
     const Code<Message Function(String name, Uri uri_)>(
-        "LocalDefinitionHidesExport", templateLocalDefinitionHidesExport,
+        "LocalDefinitionHidesExport",
         severity: Severity.ignored);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsLocalDefinitionHidesExport(String name, Uri uri_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeLocalDefinitionHidesExport,
       message: """Local definition of '${name}' hides export from '${uri}'.""",
       arguments: {'name': name, 'uri': uri_});
@@ -6297,14 +6185,14 @@
 const Code<Message Function(String name, Uri uri_)>
     codeLocalDefinitionHidesImport =
     const Code<Message Function(String name, Uri uri_)>(
-        "LocalDefinitionHidesImport", templateLocalDefinitionHidesImport,
+        "LocalDefinitionHidesImport",
         severity: Severity.ignored);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsLocalDefinitionHidesImport(String name, Uri uri_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeLocalDefinitionHidesImport,
       message: """Local definition of '${name}' hides import from '${uri}'.""",
       arguments: {'name': name, 'uri': uri_});
@@ -6406,8 +6294,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeMethodNotFound =
-    const Code<Message Function(String name)>(
-        "MethodNotFound", templateMethodNotFound,
+    const Code<Message Function(String name)>("MethodNotFound",
         analyzerCodes: <String>["UNDEFINED_METHOD"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6480,12 +6367,12 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(int count)> codeMissingExplicitTypeArguments =
-    const Code<Message Function(int count)>(
-        "MissingExplicitTypeArguments", templateMissingExplicitTypeArguments,
+    const Code<Message Function(int count)>("MissingExplicitTypeArguments",
         severity: Severity.ignored);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsMissingExplicitTypeArguments(int count) {
+  // ignore: unnecessary_null_comparison
   if (count == null) throw 'No count provided';
   return new Message(codeMissingExplicitTypeArguments,
       message: """No type arguments provided, ${count} possible.""",
@@ -6535,8 +6422,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeMissingImplementationCause =
-    const Code<Message Function(String name)>(
-        "MissingImplementationCause", templateMissingImplementationCause,
+    const Code<Message Function(String name)>("MissingImplementationCause",
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6570,7 +6456,6 @@
     codeMissingImplementationNotAbstract =
     const Code<Message Function(String name, List<String> _names)>(
         "MissingImplementationNotAbstract",
-        templateMissingImplementationNotAbstract,
         analyzerCodes: <String>["CONCRETE_CLASS_WITH_ABSTRACT_MEMBER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6639,13 +6524,12 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Uri uri_)> codeMissingPartOf =
-    const Code<Message Function(Uri uri_)>(
-        "MissingPartOf", templateMissingPartOf,
+    const Code<Message Function(Uri uri_)>("MissingPartOf",
         analyzerCodes: <String>["PART_OF_NON_PART"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsMissingPartOf(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeMissingPartOf,
       message:
           """Can't use '${uri}' as a part, because it has no 'part of' declaration.""",
@@ -6707,7 +6591,7 @@
 const Code<Message Function(String string, String string2)>
     codeModifierOutOfOrder =
     const Code<Message Function(String string, String string2)>(
-        "ModifierOutOfOrder", templateModifierOutOfOrder,
+        "ModifierOutOfOrder",
         index: 56);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6818,7 +6702,6 @@
 const Code<Message Function(String name, String name2)> codeNamedMixinOverride =
     const Code<Message Function(String name, String name2)>(
   "NamedMixinOverride",
-  templateNamedMixinOverride,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6895,7 +6778,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeNoFormals =
-    const Code<Message Function(Token token)>("NoFormals", templateNoFormals,
+    const Code<Message Function(Token token)>("NoFormals",
         analyzerCodes: <String>["MISSING_FUNCTION_PARAMETERS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6916,8 +6799,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeNoSuchNamedParameter =
-    const Code<Message Function(String name)>(
-        "NoSuchNamedParameter", templateNoSuchNamedParameter,
+    const Code<Message Function(String name)>("NoSuchNamedParameter",
         analyzerCodes: <String>["UNDEFINED_NAMED_PARAMETER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6963,7 +6845,7 @@
 const Code<Message Function(String character, int codePoint)>
     codeNonAsciiIdentifier =
     const Code<Message Function(String character, int codePoint)>(
-        "NonAsciiIdentifier", templateNonAsciiIdentifier,
+        "NonAsciiIdentifier",
         analyzerCodes: <String>["ILLEGAL_CHARACTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6990,8 +6872,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(int codePoint)> codeNonAsciiWhitespace =
-    const Code<Message Function(int codePoint)>(
-        "NonAsciiWhitespace", templateNonAsciiWhitespace,
+    const Code<Message Function(int codePoint)>("NonAsciiWhitespace",
         analyzerCodes: <String>["ILLEGAL_CHARACTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7049,7 +6930,6 @@
 const Code<Message Function(String name)> codeNonNullableNotAssignedError =
     const Code<Message Function(String name)>(
   "NonNullableNotAssignedError",
-  templateNonNullableNotAssignedError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7087,7 +6967,6 @@
 const Code<Message Function(String string)> codeNonNullableOptOutExplicit =
     const Code<Message Function(String string)>(
   "NonNullableOptOutExplicit",
-  templateNonNullableOptOutExplicit,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7115,7 +6994,6 @@
 const Code<Message Function(String string)> codeNonNullableOptOutImplicit =
     const Code<Message Function(String string)>(
   "NonNullableOptOutImplicit",
-  templateNonNullableOptOutImplicit,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7149,8 +7027,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeNonSimpleBoundViaReference =
-    const Code<Message Function(String name)>(
-        "NonSimpleBoundViaReference", templateNonSimpleBoundViaReference,
+    const Code<Message Function(String name)>("NonSimpleBoundViaReference",
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7174,8 +7051,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeNonSimpleBoundViaVariable =
-    const Code<Message Function(String name)>(
-        "NonSimpleBoundViaVariable", templateNonSimpleBoundViaVariable,
+    const Code<Message Function(String name)>("NonSimpleBoundViaVariable",
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7233,7 +7109,7 @@
 const Code<Message Function(String name, String name2)>
     codeNotAPrefixInTypeAnnotation =
     const Code<Message Function(String name, String name2)>(
-        "NotAPrefixInTypeAnnotation", templateNotAPrefixInTypeAnnotation,
+        "NotAPrefixInTypeAnnotation",
         analyzerCodes: <String>["NOT_A_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7256,7 +7132,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeNotAType =
-    const Code<Message Function(String name)>("NotAType", templateNotAType,
+    const Code<Message Function(String name)>("NotAType",
         analyzerCodes: <String>["NOT_A_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7292,7 +7168,6 @@
 const Code<Message Function(Token token)> codeNotBinaryOperator =
     const Code<Message Function(Token token)>(
   "NotBinaryOperator",
-  templateNotBinaryOperator,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7311,8 +7186,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string)> codeNotConstantExpression =
-    const Code<Message Function(String string)>(
-        "NotConstantExpression", templateNotConstantExpression,
+    const Code<Message Function(String string)>("NotConstantExpression",
         analyzerCodes: <String>["NOT_CONSTANT_EXPRESSION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7347,7 +7221,6 @@
 const Code<Message Function(String name)> codeNullableInterfaceError =
     const Code<Message Function(String name)>(
   "NullableInterfaceError",
-  templateNullableInterfaceError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7370,7 +7243,6 @@
 const Code<Message Function(String name)> codeNullableMixinError =
     const Code<Message Function(String name)>(
   "NullableMixinError",
-  templateNullableMixinError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7402,7 +7274,6 @@
 const Code<Message Function(String name)> codeNullableSuperclassError =
     const Code<Message Function(String name)>(
   "NullableSuperclassError",
-  templateNullableSuperclassError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7425,7 +7296,6 @@
 const Code<Message Function(String name)> codeNullableTearoffError =
     const Code<Message Function(String name)>(
   "NullableTearoffError",
-  templateNullableTearoffError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7485,9 +7355,9 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeOperatorMinusParameterMismatch =
     const Code<Message Function(String name)>("OperatorMinusParameterMismatch",
-        templateOperatorMinusParameterMismatch, analyzerCodes: <String>[
-  "WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR_MINUS"
-]);
+        analyzerCodes: <String>[
+      "WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR_MINUS"
+    ]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsOperatorMinusParameterMismatch(String name) {
@@ -7511,7 +7381,6 @@
 const Code<Message Function(String name)> codeOperatorParameterMismatch0 =
     const Code<Message Function(String name)>(
   "OperatorParameterMismatch0",
-  templateOperatorParameterMismatch0,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7533,8 +7402,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeOperatorParameterMismatch1 =
-    const Code<Message Function(String name)>(
-        "OperatorParameterMismatch1", templateOperatorParameterMismatch1,
+    const Code<Message Function(String name)>("OperatorParameterMismatch1",
         analyzerCodes: <String>["WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7556,8 +7424,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeOperatorParameterMismatch2 =
-    const Code<Message Function(String name)>(
-        "OperatorParameterMismatch2", templateOperatorParameterMismatch2,
+    const Code<Message Function(String name)>("OperatorParameterMismatch2",
         analyzerCodes: <String>["WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7597,8 +7464,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeOverriddenMethodCause =
-    const Code<Message Function(String name)>(
-        "OverriddenMethodCause", templateOverriddenMethodCause,
+    const Code<Message Function(String name)>("OverriddenMethodCause",
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7625,7 +7491,7 @@
 const Code<Message Function(String name, String name2)>
     codeOverrideFewerNamedArguments =
     const Code<Message Function(String name, String name2)>(
-        "OverrideFewerNamedArguments", templateOverrideFewerNamedArguments,
+        "OverrideFewerNamedArguments",
         analyzerCodes: <String>["INVALID_OVERRIDE_NAMED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7656,7 +7522,6 @@
     codeOverrideFewerPositionalArguments =
     const Code<Message Function(String name, String name2)>(
         "OverrideFewerPositionalArguments",
-        templateOverrideFewerPositionalArguments,
         analyzerCodes: <String>["INVALID_OVERRIDE_POSITIONAL"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7689,7 +7554,6 @@
     codeOverrideMismatchNamedParameter =
     const Code<Message Function(String name, String name2, String name3)>(
         "OverrideMismatchNamedParameter",
-        templateOverrideMismatchNamedParameter,
         analyzerCodes: <String>["INVALID_OVERRIDE_NAMED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7720,7 +7584,6 @@
     codeOverrideMismatchRequiredNamedParameter =
     const Code<Message Function(String name, String name2, String name3)>(
   "OverrideMismatchRequiredNamedParameter",
-  templateOverrideMismatchRequiredNamedParameter,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7753,7 +7616,7 @@
 const Code<Message Function(String name, String name2)>
     codeOverrideMoreRequiredArguments =
     const Code<Message Function(String name, String name2)>(
-        "OverrideMoreRequiredArguments", templateOverrideMoreRequiredArguments,
+        "OverrideMoreRequiredArguments",
         analyzerCodes: <String>["INVALID_OVERRIDE_REQUIRED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7783,7 +7646,7 @@
 const Code<Message Function(String name, String name2)>
     codeOverrideTypeVariablesMismatch =
     const Code<Message Function(String name, String name2)>(
-        "OverrideTypeVariablesMismatch", templateOverrideTypeVariablesMismatch,
+        "OverrideTypeVariablesMismatch",
         analyzerCodes: <String>["INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7810,14 +7673,13 @@
 const Code<Message Function(String name, Uri uri_)> codePackageNotFound =
     const Code<Message Function(String name, Uri uri_)>(
   "PackageNotFound",
-  templatePackageNotFound,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsPackageNotFound(String name, Uri uri_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codePackageNotFound,
       message: """Could not resolve the package '${name}' in '${uri}'.""",
       arguments: {'name': name, 'uri': uri_});
@@ -7833,7 +7695,6 @@
 const Code<Message Function(String string)> codePackagesFileFormat =
     const Code<Message Function(String string)>(
   "PackagesFileFormat",
-  templatePackagesFileFormat,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7892,13 +7753,12 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Uri uri_)> codePartOfInLibrary =
-    const Code<Message Function(Uri uri_)>(
-        "PartOfInLibrary", templatePartOfInLibrary,
+    const Code<Message Function(Uri uri_)>("PartOfInLibrary",
         analyzerCodes: <String>["IMPORT_OF_NON_LIBRARY"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsPartOfInLibrary(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codePartOfInLibrary,
       message:
           """Can't import '${uri}', because it has a 'part of' declaration.""",
@@ -7923,13 +7783,13 @@
 const Code<Message Function(Uri uri_, String name, String name2)>
     codePartOfLibraryNameMismatch =
     const Code<Message Function(Uri uri_, String name, String name2)>(
-        "PartOfLibraryNameMismatch", templatePartOfLibraryNameMismatch,
+        "PartOfLibraryNameMismatch",
         analyzerCodes: <String>["PART_OF_DIFFERENT_LIBRARY"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsPartOfLibraryNameMismatch(
     Uri uri_, String name, String name2) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
   if (name2.isEmpty) throw 'No name provided';
@@ -7994,14 +7854,14 @@
 const Code<Message Function(Uri uri_, Uri uri2_, Uri uri3_)>
     codePartOfUriMismatch =
     const Code<Message Function(Uri uri_, Uri uri2_, Uri uri3_)>(
-        "PartOfUriMismatch", templatePartOfUriMismatch,
+        "PartOfUriMismatch",
         analyzerCodes: <String>["PART_OF_DIFFERENT_LIBRARY"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsPartOfUriMismatch(Uri uri_, Uri uri2_, Uri uri3_) {
-  String uri = relativizeUri(uri_);
-  String uri2 = relativizeUri(uri2_);
-  String uri3 = relativizeUri(uri3_);
+  String? uri = relativizeUri(uri_);
+  String? uri2 = relativizeUri(uri2_);
+  String? uri3 = relativizeUri(uri3_);
   return new Message(codePartOfUriMismatch,
       message:
           """Using '${uri}' as part of '${uri2}' but its 'part of' declaration says '${uri3}'.""",
@@ -8026,13 +7886,13 @@
 const Code<Message Function(Uri uri_, Uri uri2_, String name)>
     codePartOfUseUri =
     const Code<Message Function(Uri uri_, Uri uri2_, String name)>(
-        "PartOfUseUri", templatePartOfUseUri,
+        "PartOfUseUri",
         analyzerCodes: <String>["PART_OF_UNNAMED_LIBRARY"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsPartOfUseUri(Uri uri_, Uri uri2_, String name) {
-  String uri = relativizeUri(uri_);
-  String uri2 = relativizeUri(uri2_);
+  String? uri = relativizeUri(uri_);
+  String? uri2 = relativizeUri(uri2_);
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
   return new Message(codePartOfUseUri,
@@ -8058,12 +7918,12 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Uri uri_)> codePartTwice =
-    const Code<Message Function(Uri uri_)>("PartTwice", templatePartTwice,
+    const Code<Message Function(Uri uri_)>("PartTwice",
         analyzerCodes: <String>["DUPLICATE_PART"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsPartTwice(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codePartTwice,
       message: """Can't use '${uri}' as a part more than once.""",
       arguments: {'uri': uri_});
@@ -8117,14 +7977,13 @@
 const Code<Message Function(String name, Uri uri_)> codePatchInjectionFailed =
     const Code<Message Function(String name, Uri uri_)>(
   "PatchInjectionFailed",
-  templatePatchInjectionFailed,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsPatchInjectionFailed(String name, Uri uri_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codePatchInjectionFailed,
       message: """Can't inject '${name}' into '${uri}'.""",
       tip: """Try adding '@patch'.""",
@@ -8262,8 +8121,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeRedirectionTargetNotFound =
-    const Code<Message Function(String name)>(
-        "RedirectionTargetNotFound", templateRedirectionTargetNotFound,
+    const Code<Message Function(String name)>("RedirectionTargetNotFound",
         analyzerCodes: <String>["REDIRECT_TO_MISSING_CONSTRUCTOR"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8289,7 +8147,6 @@
     codeRequiredNamedParameterHasDefaultValueError =
     const Code<Message Function(String name)>(
   "RequiredNamedParameterHasDefaultValueError",
-  templateRequiredNamedParameterHasDefaultValueError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8380,12 +8237,11 @@
 const Code<Message Function(Uri uri_)> codeSdkRootNotFound =
     const Code<Message Function(Uri uri_)>(
   "SdkRootNotFound",
-  templateSdkRootNotFound,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSdkRootNotFound(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeSdkRootNotFound,
       message: """SDK root directory not found: ${uri}.""",
       arguments: {'uri': uri_});
@@ -8406,12 +8262,11 @@
 const Code<Message Function(Uri uri_)> codeSdkSpecificationNotFound =
     const Code<Message Function(Uri uri_)>(
   "SdkSpecificationNotFound",
-  templateSdkSpecificationNotFound,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSdkSpecificationNotFound(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeSdkSpecificationNotFound,
       message: """SDK libraries specification not found: ${uri}.""",
       tip:
@@ -8429,12 +8284,11 @@
 const Code<Message Function(Uri uri_)> codeSdkSummaryNotFound =
     const Code<Message Function(Uri uri_)>(
   "SdkSummaryNotFound",
-  templateSdkSummaryNotFound,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSdkSummaryNotFound(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeSdkSummaryNotFound,
       message: """SDK summary not found: ${uri}.""", arguments: {'uri': uri_});
 }
@@ -8476,8 +8330,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeSetterNotFound =
-    const Code<Message Function(String name)>(
-        "SetterNotFound", templateSetterNotFound,
+    const Code<Message Function(String name)>("SetterNotFound",
         analyzerCodes: <String>["UNDEFINED_SETTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8529,18 +8382,22 @@
         num _num3)> codeSourceBodySummary = const Code<
     Message Function(int count, int count2, num _num1, num _num2, num _num3)>(
   "SourceBodySummary",
-  templateSourceBodySummary,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSourceBodySummary(
     int count, int count2, num _num1, num _num2, num _num3) {
+  // ignore: unnecessary_null_comparison
   if (count == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
   if (count2 == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
   if (_num1 == null) throw 'No number provided';
   String num1 = _num1.toStringAsFixed(3);
+  // ignore: unnecessary_null_comparison
   if (_num2 == null) throw 'No number provided';
   String num2 = _num2.toStringAsFixed(3).padLeft(12);
+  // ignore: unnecessary_null_comparison
   if (_num3 == null) throw 'No number provided';
   String num3 = _num3.toStringAsFixed(3).padLeft(12);
   return new Message(codeSourceBodySummary,
@@ -8580,18 +8437,22 @@
         num _num3)> codeSourceOutlineSummary = const Code<
     Message Function(int count, int count2, num _num1, num _num2, num _num3)>(
   "SourceOutlineSummary",
-  templateSourceOutlineSummary,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSourceOutlineSummary(
     int count, int count2, num _num1, num _num2, num _num3) {
+  // ignore: unnecessary_null_comparison
   if (count == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
   if (count2 == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
   if (_num1 == null) throw 'No number provided';
   String num1 = _num1.toStringAsFixed(3);
+  // ignore: unnecessary_null_comparison
   if (_num2 == null) throw 'No number provided';
   String num2 = _num2.toStringAsFixed(3).padLeft(12);
+  // ignore: unnecessary_null_comparison
   if (_num3 == null) throw 'No number provided';
   String num3 = _num3.toStringAsFixed(3).padLeft(12);
   return new Message(codeSourceOutlineSummary,
@@ -8701,7 +8562,6 @@
     codeStrongModeNNBDPackageOptOut =
     const Code<Message Function(List<String> _names)>(
   "StrongModeNNBDPackageOptOut",
-  templateStrongModeNNBDPackageOptOut,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8777,8 +8637,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeSuperclassHasNoConstructor =
-    const Code<Message Function(String name)>(
-        "SuperclassHasNoConstructor", templateSuperclassHasNoConstructor,
+    const Code<Message Function(String name)>("SuperclassHasNoConstructor",
         analyzerCodes: <String>[
       "UNDEFINED_CONSTRUCTOR_IN_INITIALIZER",
       "UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT"
@@ -8808,7 +8667,6 @@
     codeSuperclassHasNoDefaultConstructor =
     const Code<Message Function(String name)>(
         "SuperclassHasNoDefaultConstructor",
-        templateSuperclassHasNoDefaultConstructor,
         analyzerCodes: <String>["NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8829,8 +8687,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeSuperclassHasNoGetter =
-    const Code<Message Function(String name)>(
-        "SuperclassHasNoGetter", templateSuperclassHasNoGetter,
+    const Code<Message Function(String name)>("SuperclassHasNoGetter",
         analyzerCodes: <String>["UNDEFINED_SUPER_GETTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8850,8 +8707,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeSuperclassHasNoMethod =
-    const Code<Message Function(String name)>(
-        "SuperclassHasNoMethod", templateSuperclassHasNoMethod,
+    const Code<Message Function(String name)>("SuperclassHasNoMethod",
         analyzerCodes: <String>["UNDEFINED_SUPER_METHOD"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8871,8 +8727,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeSuperclassHasNoSetter =
-    const Code<Message Function(String name)>(
-        "SuperclassHasNoSetter", templateSuperclassHasNoSetter,
+    const Code<Message Function(String name)>("SuperclassHasNoSetter",
         analyzerCodes: <String>["UNDEFINED_SUPER_SETTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8898,7 +8753,6 @@
 const Code<Message Function(String name)> codeSuperclassMethodArgumentMismatch =
     const Code<Message Function(String name)>(
   "SuperclassMethodArgumentMismatch",
-  templateSuperclassMethodArgumentMismatch,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8927,8 +8781,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeSupertypeIsIllegal =
-    const Code<Message Function(String name)>(
-        "SupertypeIsIllegal", templateSupertypeIsIllegal,
+    const Code<Message Function(String name)>("SupertypeIsIllegal",
         analyzerCodes: <String>["EXTENDS_NON_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8949,8 +8802,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeSupertypeIsTypeVariable =
-    const Code<Message Function(String name)>(
-        "SupertypeIsTypeVariable", templateSupertypeIsTypeVariable,
+    const Code<Message Function(String name)>("SupertypeIsTypeVariable",
         analyzerCodes: <String>["EXTENDS_NON_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9021,8 +8873,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeThisAccessInFieldInitializer =
-    const Code<Message Function(String name)>(
-        "ThisAccessInFieldInitializer", templateThisAccessInFieldInitializer,
+    const Code<Message Function(String name)>("ThisAccessInFieldInitializer",
         analyzerCodes: <String>["THIS_ACCESS_FROM_FIELD_INITIALIZER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9066,7 +8917,6 @@
     codeThisOrSuperAccessInFieldInitializer =
     const Code<Message Function(String string)>(
         "ThisOrSuperAccessInFieldInitializer",
-        templateThisOrSuperAccessInFieldInitializer,
         analyzerCodes: <String>["THIS_ACCESS_FROM_INITIALIZER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9090,13 +8940,14 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(int count, int count2)> codeTooFewArguments =
-    const Code<Message Function(int count, int count2)>(
-        "TooFewArguments", templateTooFewArguments,
+    const Code<Message Function(int count, int count2)>("TooFewArguments",
         analyzerCodes: <String>["NOT_ENOUGH_REQUIRED_ARGUMENTS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsTooFewArguments(int count, int count2) {
+  // ignore: unnecessary_null_comparison
   if (count == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
   if (count2 == null) throw 'No count provided';
   return new Message(codeTooFewArguments,
       message:
@@ -9118,13 +8969,14 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(int count, int count2)> codeTooManyArguments =
-    const Code<Message Function(int count, int count2)>(
-        "TooManyArguments", templateTooManyArguments,
+    const Code<Message Function(int count, int count2)>("TooManyArguments",
         analyzerCodes: <String>["EXTRA_POSITIONAL_ARGUMENTS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsTooManyArguments(int count, int count2) {
+  // ignore: unnecessary_null_comparison
   if (count == null) throw 'No count provided';
+  // ignore: unnecessary_null_comparison
   if (count2 == null) throw 'No count provided';
   return new Message(codeTooManyArguments,
       message:
@@ -9162,12 +9014,12 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(int count)> codeTypeArgumentMismatch =
-    const Code<Message Function(int count)>(
-        "TypeArgumentMismatch", templateTypeArgumentMismatch,
+    const Code<Message Function(int count)>("TypeArgumentMismatch",
         analyzerCodes: <String>["WRONG_NUMBER_OF_TYPE_ARGUMENTS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsTypeArgumentMismatch(int count) {
+  // ignore: unnecessary_null_comparison
   if (count == null) throw 'No count provided';
   return new Message(codeTypeArgumentMismatch,
       message: """Expected ${count} type arguments.""",
@@ -9185,8 +9037,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeTypeArgumentsOnTypeVariable =
-    const Code<Message Function(String name)>(
-        "TypeArgumentsOnTypeVariable", templateTypeArgumentsOnTypeVariable,
+    const Code<Message Function(String name)>("TypeArgumentsOnTypeVariable",
         index: 13);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9217,8 +9068,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeTypeNotFound =
-    const Code<Message Function(String name)>(
-        "TypeNotFound", templateTypeNotFound,
+    const Code<Message Function(String name)>("TypeNotFound",
         analyzerCodes: <String>["UNDEFINED_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9239,14 +9089,13 @@
 const Code<Message Function(String name, Uri uri_)> codeTypeOrigin =
     const Code<Message Function(String name, Uri uri_)>(
   "TypeOrigin",
-  templateTypeOrigin,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsTypeOrigin(String name, Uri uri_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeTypeOrigin,
       message: """'${name}' is from '${uri}'.""",
       arguments: {'name': name, 'uri': uri_});
@@ -9264,15 +9113,14 @@
     codeTypeOriginWithFileUri =
     const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
   "TypeOriginWithFileUri",
-  templateTypeOriginWithFileUri,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsTypeOriginWithFileUri(String name, Uri uri_, Uri uri2_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
-  String uri = relativizeUri(uri_);
-  String uri2 = relativizeUri(uri2_);
+  String? uri = relativizeUri(uri_);
+  String? uri2 = relativizeUri(uri2_);
   return new Message(codeTypeOriginWithFileUri,
       message: """'${name}' is from '${uri}' ('${uri2}').""",
       arguments: {'name': name, 'uri': uri_, 'uri2': uri2_});
@@ -9298,7 +9146,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeTypeVariableDuplicatedNameCause =
     const Code<Message Function(String name)>("TypeVariableDuplicatedNameCause",
-        templateTypeVariableDuplicatedNameCause,
         severity: Severity.context);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9436,8 +9283,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeUnexpectedModifierInNonNnbd =
-    const Code<Message Function(Token token)>(
-        "UnexpectedModifierInNonNnbd", templateUnexpectedModifierInNonNnbd,
+    const Code<Message Function(Token token)>("UnexpectedModifierInNonNnbd",
         analyzerCodes: <String>["UNEXPECTED_TOKEN"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9457,8 +9303,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeUnexpectedToken =
-    const Code<Message Function(Token token)>(
-        "UnexpectedToken", templateUnexpectedToken,
+    const Code<Message Function(Token token)>("UnexpectedToken",
         analyzerCodes: <String>["UNEXPECTED_TOKEN"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9478,8 +9323,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String string, Token token)> codeUnmatchedToken =
-    const Code<Message Function(String string, Token token)>(
-        "UnmatchedToken", templateUnmatchedToken,
+    const Code<Message Function(String string, Token token)>("UnmatchedToken",
         analyzerCodes: <String>["EXPECTED_TOKEN"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9507,7 +9351,6 @@
     codeUnresolvedPrefixInTypeAnnotation =
     const Code<Message Function(String name, String name2)>(
         "UnresolvedPrefixInTypeAnnotation",
-        templateUnresolvedPrefixInTypeAnnotation,
         analyzerCodes: <String>["NOT_A_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9533,7 +9376,6 @@
 const Code<Message Function(String string)> codeUnspecified =
     const Code<Message Function(String string)>(
   "Unspecified",
-  templateUnspecified,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9551,8 +9393,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Token token)> codeUnsupportedOperator =
-    const Code<Message Function(Token token)>(
-        "UnsupportedOperator", templateUnsupportedOperator,
+    const Code<Message Function(Token token)>("UnsupportedOperator",
         analyzerCodes: <String>["UNSUPPORTED_OPERATOR"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9594,7 +9435,7 @@
 const Code<Message Function(String string, String string2)>
     codeUnterminatedString =
     const Code<Message Function(String string, String string2)>(
-        "UnterminatedString", templateUnterminatedString,
+        "UnterminatedString",
         analyzerCodes: <String>["UNTERMINATED_STRING_LITERAL"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9621,13 +9462,12 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(Uri uri_)> codeUntranslatableUri =
-    const Code<Message Function(Uri uri_)>(
-        "UntranslatableUri", templateUntranslatableUri,
+    const Code<Message Function(Uri uri_)>("UntranslatableUri",
         analyzerCodes: <String>["URI_DOES_NOT_EXIST"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsUntranslatableUri(Uri uri_) {
-  String uri = relativizeUri(uri_);
+  String? uri = relativizeUri(uri_);
   return new Message(codeUntranslatableUri,
       message: """Not found: '${uri}'""", arguments: {'uri': uri_});
 }
@@ -9641,8 +9481,7 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeUseOfDeprecatedIdentifier =
-    const Code<Message Function(String name)>(
-        "UseOfDeprecatedIdentifier", templateUseOfDeprecatedIdentifier,
+    const Code<Message Function(String name)>("UseOfDeprecatedIdentifier",
         severity: Severity.ignored);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9666,7 +9505,6 @@
     codeValueForRequiredParameterNotProvidedError =
     const Code<Message Function(String name)>(
   "ValueForRequiredParameterNotProvidedError",
-  templateValueForRequiredParameterNotProvidedError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9751,7 +9589,6 @@
     codeWebLiteralCannotBeRepresentedExactly =
     const Code<Message Function(String string, String string2)>(
   "WebLiteralCannotBeRepresentedExactly",
-  templateWebLiteralCannotBeRepresentedExactly,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/diagnostic_message.dart b/pkg/_fe_analyzer_shared/lib/src/messages/diagnostic_message.dart
index 7146258..14540d9 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/diagnostic_message.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/diagnostic_message.dart
@@ -35,13 +35,13 @@
 
   Severity get severity;
 
-  Iterable<Uri> get involvedFiles;
+  Iterable<Uri>? get involvedFiles;
 
-  String get codeName;
+  String? get codeName;
 }
 
 /// This method is subject to change.
-Uri getMessageUri(DiagnosticMessage message) {
+Uri? getMessageUri(DiagnosticMessage message) {
   return message is FormattedMessage
       ? message.uri
       : message is DiagnosticMessageFromJson
@@ -50,22 +50,22 @@
 }
 
 /// This method is subject to change.
-int getMessageCharOffset(DiagnosticMessage message) {
+int? getMessageCharOffset(DiagnosticMessage message) {
   return message is FormattedMessage ? message.charOffset : null;
 }
 
 /// This method is subject to change.
-int getMessageLength(DiagnosticMessage message) {
+int? getMessageLength(DiagnosticMessage message) {
   return message is FormattedMessage ? message.length : null;
 }
 
 /// This method is subject to change.
-Code getMessageCodeObject(DiagnosticMessage message) {
+Code? getMessageCodeObject(DiagnosticMessage message) {
   return message is FormattedMessage ? message.code : null;
 }
 
 /// This method is subject to change.
-String getMessageHeaderText(DiagnosticMessage message) {
+String? getMessageHeaderText(DiagnosticMessage message) {
   return message is FormattedMessage ? message.message : null;
 }
 
@@ -75,12 +75,12 @@
 }
 
 /// This method is subject to change.
-Map<String, dynamic> getMessageArguments(DiagnosticMessage message) {
+Map<String, dynamic>? getMessageArguments(DiagnosticMessage message) {
   return message is FormattedMessage ? message.arguments : null;
 }
 
 /// This method is subject to change.
-Iterable<DiagnosticMessage> getMessageRelatedInformation(
+Iterable<DiagnosticMessage>? getMessageRelatedInformation(
     DiagnosticMessage message) {
   return message is FormattedMessage ? message.relatedInformation : null;
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/block_kind.dart b/pkg/_fe_analyzer_shared/lib/src/parser/block_kind.dart
index 46c0f8d..539fb14 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/block_kind.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/block_kind.dart
@@ -13,7 +13,7 @@
   /// [templateExpectedClassOrMixinBody].
   ///
   /// If `null` the generic [templateExpectedButGot] is used instead.
-  String get missingBlockName => useNameForMissingBlock ? name : null;
+  String? get missingBlockName => useNameForMissingBlock ? name : null;
 
   String toString() => 'BlockKind($name)';
 
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/class_member_parser.dart b/pkg/_fe_analyzer_shared/lib/src/parser/class_member_parser.dart
index c41be78..d42c6ed 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/class_member_parser.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/class_member_parser.dart
@@ -15,7 +15,7 @@
 /// Parser similar to [TopLevelParser] but also parses class members (excluding
 /// their bodies).
 class ClassMemberParser extends Parser {
-  Parser skipParser;
+  Parser? skipParser;
 
   ClassMemberParser(Listener listener) : super(listener);
 
@@ -26,7 +26,7 @@
 
   @override
   Token parseIdentifierExpression(Token token) {
-    return token.next;
+    return token.next!;
   }
 
   Token skipExpression(Token token) {
@@ -35,7 +35,8 @@
     // not triggered during the second parse.
     // When the parser supports not doing token stream rewriting, use that
     // feature together with a no-op listener instead.
-    skipParser ??= new Parser(new ErrorDelegationListener(listener));
+    this.skipParser ??= new Parser(new ErrorDelegationListener(listener));
+    Parser skipParser = this.skipParser!;
     skipParser.mayParseFunctionExpressions = mayParseFunctionExpressions;
     skipParser.asyncState = asyncState;
     skipParser.loopState = loopState;
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
index bca2267..0274d64 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
@@ -7,13 +7,13 @@
 import 'parser.dart';
 
 class ForwardingListener implements Listener {
-  Listener listener;
+  Listener? listener;
   bool forwardErrors = true;
 
   ForwardingListener([this.listener]);
 
   @override
-  Uri get uri => listener?.uri;
+  Uri? get uri => listener?.uri;
 
   @override
   void beginArguments(Token token) {
@@ -61,7 +61,7 @@
   }
 
   @override
-  void beginClassDeclaration(Token begin, Token abstractToken, Token name) {
+  void beginClassDeclaration(Token begin, Token? abstractToken, Token name) {
     listener?.beginClassDeclaration(begin, abstractToken, name);
   }
 
@@ -151,13 +151,13 @@
   }
 
   @override
-  void beginExtensionDeclaration(Token extensionKeyword, Token name) {
+  void beginExtensionDeclaration(Token extensionKeyword, Token? name) {
     listener?.beginExtensionDeclaration(extensionKeyword, name);
   }
 
   @override
   void beginFactoryMethod(
-      Token lastConsumed, Token externalToken, Token constToken) {
+      Token lastConsumed, Token? externalToken, Token? constToken) {
     listener?.beginFactoryMethod(lastConsumed, externalToken, constToken);
   }
 
@@ -167,7 +167,7 @@
   }
 
   @override
-  void beginForControlFlow(Token awaitToken, Token forToken) {
+  void beginForControlFlow(Token? awaitToken, Token forToken) {
     listener?.beginForControlFlow(awaitToken, forToken);
   }
 
@@ -182,8 +182,8 @@
   }
 
   @override
-  void beginFormalParameter(Token token, MemberKind kind, Token requiredToken,
-      Token covariantToken, Token varFinalOrConst) {
+  void beginFormalParameter(Token token, MemberKind kind, Token? requiredToken,
+      Token? covariantToken, Token? varFinalOrConst) {
     listener?.beginFormalParameter(
         token, kind, requiredToken, covariantToken, varFinalOrConst);
   }
@@ -314,8 +314,13 @@
   }
 
   @override
-  void beginMethod(Token externalToken, Token staticToken, Token covariantToken,
-      Token varFinalOrConst, Token getOrSet, Token name) {
+  void beginMethod(
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? varFinalOrConst,
+      Token? getOrSet,
+      Token name) {
     listener?.beginMethod(externalToken, staticToken, covariantToken,
         varFinalOrConst, getOrSet, name);
   }
@@ -332,7 +337,7 @@
 
   @override
   void beginNamedMixinApplication(
-      Token begin, Token abstractToken, Token name) {
+      Token begin, Token? abstractToken, Token name) {
     listener?.beginNamedMixinApplication(begin, abstractToken, name);
   }
 
@@ -407,7 +412,7 @@
   }
 
   @override
-  void beginTopLevelMethod(Token lastConsumed, Token externalToken) {
+  void beginTopLevelMethod(Token lastConsumed, Token? externalToken) {
     listener?.beginTopLevelMethod(lastConsumed, externalToken);
   }
 
@@ -443,7 +448,7 @@
 
   @override
   void beginVariablesDeclaration(
-      Token token, Token lateToken, Token varFinalOrConst) {
+      Token token, Token? lateToken, Token? varFinalOrConst) {
     listener?.beginVariablesDeclaration(token, lateToken, varFinalOrConst);
   }
 
@@ -469,7 +474,7 @@
 
   @override
   void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis,
-      Token commaToken, Token semicolonToken) {
+      Token? commaToken, Token semicolonToken) {
     listener?.endAssert(
         assertKeyword, kind, leftParenthesis, commaToken, semicolonToken);
   }
@@ -516,8 +521,8 @@
   }
 
   @override
-  void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
+  void endClassConstructor(Token? getOrSet, Token beginToken, Token beginParam,
+      Token? beginInitializers, Token endToken) {
     listener?.endClassConstructor(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
@@ -535,12 +540,12 @@
 
   @override
   void endClassFields(
-      Token abstractToken,
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       int count,
       Token beginToken,
       Token endToken) {
@@ -557,8 +562,8 @@
   }
 
   @override
-  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
+  void endClassMethod(Token? getOrSet, Token beginToken, Token beginParam,
+      Token? beginInitializers, Token endToken) {
     listener?.endClassMethod(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
@@ -585,7 +590,7 @@
   }
 
   @override
-  void endConditionalUri(Token ifKeyword, Token leftParen, Token equalSign) {
+  void endConditionalUri(Token ifKeyword, Token leftParen, Token? equalSign) {
     listener?.endConditionalUri(ifKeyword, leftParen, equalSign);
   }
 
@@ -606,7 +611,7 @@
 
   @override
   void endConstructorReference(
-      Token start, Token periodBeforeName, Token endToken) {
+      Token start, Token? periodBeforeName, Token endToken) {
     listener?.endConstructorReference(start, periodBeforeName, endToken);
   }
 
@@ -637,8 +642,8 @@
   }
 
   @override
-  void endExtensionConstructor(Token getOrSet, Token beginToken,
-      Token beginParam, Token beginInitializers, Token endToken) {
+  void endExtensionConstructor(Token? getOrSet, Token beginToken,
+      Token beginParam, Token? beginInitializers, Token endToken) {
     listener?.endExtensionConstructor(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
@@ -657,12 +662,12 @@
 
   @override
   void endExtensionFields(
-      Token abstractToken,
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       int count,
       Token beginToken,
       Token endToken) {
@@ -679,8 +684,8 @@
   }
 
   @override
-  void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
+  void endExtensionMethod(Token? getOrSet, Token beginToken, Token beginParam,
+      Token? beginInitializers, Token endToken) {
     listener?.endExtensionMethod(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
@@ -717,11 +722,11 @@
 
   @override
   void endFormalParameter(
-      Token thisKeyword,
-      Token periodAfterThis,
+      Token? thisKeyword,
+      Token? periodAfterThis,
       Token nameToken,
-      Token initializerStart,
-      Token initializerEnd,
+      Token? initializerStart,
+      Token? initializerEnd,
       FormalParameterKind kind,
       MemberKind memberKind) {
     listener?.endFormalParameter(thisKeyword, periodAfterThis, nameToken,
@@ -760,18 +765,18 @@
   }
 
   @override
-  void endFunctionType(Token functionToken, Token questionMark) {
+  void endFunctionType(Token functionToken, Token? questionMark) {
     listener?.endFunctionType(functionToken, questionMark);
   }
 
   @override
   void endFunctionTypeAlias(
-      Token typedefKeyword, Token equals, Token endToken) {
+      Token typedefKeyword, Token? equals, Token endToken) {
     listener?.endFunctionTypeAlias(typedefKeyword, equals, endToken);
   }
 
   @override
-  void endFunctionTypedFormalParameter(Token nameToken, Token question) {
+  void endFunctionTypedFormalParameter(Token nameToken, Token? question) {
     listener?.endFunctionTypedFormalParameter(nameToken, question);
   }
 
@@ -791,7 +796,7 @@
   }
 
   @override
-  void endIfStatement(Token ifToken, Token elseToken) {
+  void endIfStatement(Token ifToken, Token? elseToken) {
     listener?.endIfStatement(ifToken, elseToken);
   }
 
@@ -801,7 +806,7 @@
   }
 
   @override
-  void endImport(Token importKeyword, Token semicolon) {
+  void endImport(Token importKeyword, Token? semicolon) {
     listener?.endImport(importKeyword, semicolon);
   }
 
@@ -827,7 +832,7 @@
   }
 
   @override
-  void endInvalidYieldStatement(Token beginToken, Token starToken,
+  void endInvalidYieldStatement(Token beginToken, Token? starToken,
       Token endToken, MessageCode errorCode) {
     listener?.endInvalidYieldStatement(
         beginToken, starToken, endToken, errorCode);
@@ -864,7 +869,7 @@
   }
 
   @override
-  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+  void endMetadata(Token beginToken, Token? periodBeforeName, Token endToken) {
     listener?.endMetadata(beginToken, periodBeforeName, endToken);
   }
 
@@ -874,8 +879,8 @@
   }
 
   @override
-  void endMixinConstructor(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
+  void endMixinConstructor(Token? getOrSet, Token beginToken, Token beginParam,
+      Token? beginInitializers, Token endToken) {
     listener?.endMixinConstructor(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
@@ -893,12 +898,12 @@
 
   @override
   void endMixinFields(
-      Token abstractToken,
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       int count,
       Token beginToken,
       Token endToken) {
@@ -915,8 +920,8 @@
   }
 
   @override
-  void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
+  void endMixinMethod(Token? getOrSet, Token beginToken, Token beginParam,
+      Token? beginInitializers, Token endToken) {
     listener?.endMixinMethod(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
@@ -928,7 +933,7 @@
 
   @override
   void endNamedMixinApplication(Token begin, Token classKeyword, Token equals,
-      Token implementsKeyword, Token endToken) {
+      Token? implementsKeyword, Token endToken) {
     listener?.endNamedMixinApplication(
         begin, classKeyword, equals, implementsKeyword, endToken);
   }
@@ -985,8 +990,8 @@
   void endSwitchCase(
       int labelCount,
       int expressionCount,
-      Token defaultKeyword,
-      Token colonAfterDefault,
+      Token? defaultKeyword,
+      Token? colonAfterDefault,
       int statementCount,
       Token firstToken,
       Token endToken) {
@@ -1016,11 +1021,11 @@
 
   @override
   void endTopLevelFields(
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       int count,
       Token beginToken,
       Token endToken) {
@@ -1029,12 +1034,13 @@
   }
 
   @override
-  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
+  void endTopLevelMethod(Token beginToken, Token? getOrSet, Token endToken) {
     listener?.endTopLevelMethod(beginToken, getOrSet, endToken);
   }
 
   @override
-  void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
+  void endTryStatement(
+      int catchCount, Token tryKeyword, Token? finallyKeyword) {
     listener?.endTryStatement(catchCount, tryKeyword, finallyKeyword);
   }
 
@@ -1050,7 +1056,7 @@
 
   @override
   void endTypeVariable(
-      Token token, int index, Token extendsOrSuper, Token variance) {
+      Token token, int index, Token? extendsOrSuper, Token? variance) {
     listener?.endTypeVariable(token, index, extendsOrSuper, variance);
   }
 
@@ -1065,7 +1071,7 @@
   }
 
   @override
-  void endVariablesDeclaration(int count, Token endToken) {
+  void endVariablesDeclaration(int count, Token? endToken) {
     listener?.endVariablesDeclaration(count, endToken);
   }
 
@@ -1080,7 +1086,7 @@
   }
 
   @override
-  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
+  void endYieldStatement(Token yieldToken, Token? starToken, Token endToken) {
     listener?.endYieldStatement(yieldToken, starToken, endToken);
   }
 
@@ -1105,7 +1111,7 @@
   }
 
   @override
-  void handleAsyncModifier(Token asyncToken, Token starToken) {
+  void handleAsyncModifier(Token? asyncToken, Token? starToken) {
     listener?.handleAsyncModifier(asyncToken, starToken);
   }
 
@@ -1121,17 +1127,17 @@
   }
 
   @override
-  void handleCatchBlock(Token onKeyword, Token catchKeyword, Token comma) {
+  void handleCatchBlock(Token? onKeyword, Token? catchKeyword, Token? comma) {
     listener?.handleCatchBlock(onKeyword, catchKeyword, comma);
   }
 
   @override
-  void handleClassExtends(Token extendsKeyword, int typeCount) {
+  void handleClassExtends(Token? extendsKeyword, int typeCount) {
     listener?.handleClassExtends(extendsKeyword, typeCount);
   }
 
   @override
-  void handleClassHeader(Token begin, Token classKeyword, Token nativeToken) {
+  void handleClassHeader(Token begin, Token classKeyword, Token? nativeToken) {
     listener?.handleClassHeader(begin, classKeyword, nativeToken);
   }
 
@@ -1142,7 +1148,7 @@
 
   @override
   void handleClassOrMixinImplements(
-      Token implementsKeyword, int interfacesCount) {
+      Token? implementsKeyword, int interfacesCount) {
     listener?.handleClassOrMixinImplements(implementsKeyword, interfacesCount);
   }
 
@@ -1153,7 +1159,7 @@
 
   @override
   void handleCommentReference(
-      Token newKeyword, Token prefix, Token period, Token token) {
+      Token? newKeyword, Token? prefix, Token? period, Token token) {
     listener?.handleCommentReference(newKeyword, prefix, period, token);
   }
 
@@ -1204,7 +1210,7 @@
   }
 
   @override
-  void handleExpressionFunctionBody(Token arrowToken, Token endToken) {
+  void handleExpressionFunctionBody(Token arrowToken, Token? endToken) {
     listener?.handleExpressionFunctionBody(arrowToken, endToken);
   }
 
@@ -1239,7 +1245,7 @@
   }
 
   @override
-  void handleForInLoopParts(Token awaitToken, Token forToken,
+  void handleForInLoopParts(Token? awaitToken, Token forToken,
       Token leftParenthesis, Token inKeyword) {
     listener?.handleForInLoopParts(
         awaitToken, forToken, leftParenthesis, inKeyword);
@@ -1273,19 +1279,19 @@
   }
 
   @override
-  void handleImportPrefix(Token deferredKeyword, Token asKeyword) {
+  void handleImportPrefix(Token? deferredKeyword, Token? asKeyword) {
     listener?.handleImportPrefix(deferredKeyword, asKeyword);
   }
 
   @override
   void handleIndexedExpression(
-      Token question, Token openSquareBracket, Token closeSquareBracket) {
+      Token? question, Token openSquareBracket, Token closeSquareBracket) {
     listener?.handleIndexedExpression(
         question, openSquareBracket, closeSquareBracket);
   }
 
   @override
-  void handleInterpolationExpression(Token leftBracket, Token rightBracket) {
+  void handleInterpolationExpression(Token leftBracket, Token? rightBracket) {
     listener?.handleInterpolationExpression(leftBracket, rightBracket);
   }
 
@@ -1344,7 +1350,7 @@
   }
 
   @override
-  void handleIsOperator(Token isOperator, Token not) {
+  void handleIsOperator(Token isOperator, Token? not) {
     listener?.handleIsOperator(isOperator, not);
   }
 
@@ -1370,7 +1376,7 @@
 
   @override
   void handleLiteralList(
-      int count, Token beginToken, Token constKeyword, Token endToken) {
+      int count, Token beginToken, Token? constKeyword, Token endToken) {
     listener?.handleLiteralList(count, beginToken, constKeyword, endToken);
   }
 
@@ -1388,7 +1394,7 @@
   void handleLiteralSetOrMap(
     int count,
     Token leftBrace,
-    Token constKeyword,
+    Token? constKeyword,
     Token rightBrace,
     // TODO(danrubel): hasSetEntry parameter exists for replicating existing
     // behavior and will be removed once unified collection has been enabled
@@ -1404,7 +1410,7 @@
   }
 
   @override
-  void handleMixinOn(Token onKeyword, int typeCount) {
+  void handleMixinOn(Token? onKeyword, int typeCount) {
     listener?.handleMixinOn(onKeyword, typeCount);
   }
 
@@ -1542,7 +1548,7 @@
   }
 
   @override
-  void handleRecoverImport(Token semicolon) {
+  void handleRecoverImport(Token? semicolon) {
     listener?.handleRecoverImport(semicolon);
   }
 
@@ -1597,7 +1603,7 @@
   }
 
   @override
-  void handleType(Token beginToken, Token questionMark) {
+  void handleType(Token beginToken, Token? questionMark) {
     listener?.handleType(beginToken, questionMark);
   }
 
@@ -1648,7 +1654,7 @@
   }
 
   @override
-  void reportVarianceModifierNotEnabled(Token variance) {
+  void reportVarianceModifierNotEnabled(Token? variance) {
     listener?.reportVarianceModifierNotEnabled(variance);
   }
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/identifier_context.dart b/pkg/_fe_analyzer_shared/lib/src/parser/identifier_context.dart
index 42c8fe2..6b81262 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/identifier_context.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/identifier_context.dart
@@ -276,7 +276,7 @@
       this.isContinuation: false,
       this.isScopeReference: false,
       this.isBuiltInIdentifierAllowed: true,
-      bool allowedInConstantExpression,
+      bool? allowedInConstantExpression,
       this.recoveryTemplate: templateExpectedIdentifier})
       : this.allowedInConstantExpression =
             // Generally, declarations are legal in constant expressions.  A
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/identifier_context_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/identifier_context_impl.dart
index 5c94a3f..b49806d 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/identifier_context_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/identifier_context_impl.dart
@@ -22,7 +22,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       checkAsyncAwaitYieldAsIdentifier(identifier, parser);
@@ -51,7 +51,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.type.isPseudo) {
       return identifier;
@@ -89,7 +89,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     const List<String> followingValues = const [
       ';',
@@ -102,7 +102,7 @@
 
     if (identifier.isIdentifier) {
       if (!looksLikeStartOfNextTopLevelDeclaration(identifier) ||
-          isOneOfOrEof(identifier.next, followingValues)) {
+          isOneOfOrEof(identifier.next!, followingValues)) {
         return identifier;
       }
       // Although this is a valid identifier name, the import declaration
@@ -148,7 +148,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       checkAsyncAwaitYieldAsIdentifier(identifier, parser);
@@ -177,7 +177,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     const List<String> followingValues = const ['.', '==', ')'];
 
@@ -187,7 +187,7 @@
       // used as identifiers, they are more likely the start of the next
       // directive or declaration.
       if (!identifier.isTopLevelKeyword ||
-          isOneOfOrEof(identifier.next, followingValues)) {
+          isOneOfOrEof(identifier.next!, followingValues)) {
         return identifier;
       }
     }
@@ -222,7 +222,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.type.isPseudo) {
       return identifier;
@@ -260,7 +260,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       return identifier;
@@ -297,10 +297,10 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
-      if (optional('await', identifier) && identifier.next.isIdentifier) {
+      if (optional('await', identifier) && identifier.next!.isIdentifier) {
         // Although the `await` can be used in an expression,
         // it is followed by another identifier which does not form
         // a valid expression. Report an error on the `await` token
@@ -311,7 +311,7 @@
         // TODO(danrubel) Consider a new listener event so that analyzer
         // can represent this as an await expression in a context that does
         // not allow await.
-        return identifier.next;
+        return identifier.next!;
       } else {
         checkAsyncAwaitYieldAsIdentifier(identifier, parser);
       }
@@ -322,7 +322,7 @@
     Token reportErrorAt = identifier;
     if (optional(r'$', token) &&
         identifier.isKeyword &&
-        identifier.next.kind == STRING_TOKEN) {
+        identifier.next!.kind == STRING_TOKEN) {
       // Keyword used as identifier in string interpolation
       parser.reportRecoverableErrorWithToken(
           identifier, codes.templateExpectedIdentifierButGotKeyword);
@@ -340,7 +340,7 @@
               const ['.', ',', '(', ')', '[', ']', '{', '}', '?', ':', ';'])) {
         // When in doubt, consume the token to ensure we make progress
         token = identifier;
-        identifier = token.next;
+        identifier = token.next!;
       }
     }
 
@@ -359,7 +359,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       return identifier;
@@ -387,7 +387,7 @@
   Token ensureIdentifierPotentiallyRecovered(
       Token token, Parser parser, bool isRecovered) {
     // Fast path good case.
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       return identifier;
@@ -412,7 +412,7 @@
   @override
   Token ensureIdentifier(Token token, Parser parser) {
     assert(optional('.', token));
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       return identifier;
@@ -433,7 +433,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       checkAsyncAwaitYieldAsIdentifier(identifier, parser);
@@ -482,7 +482,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.type.isPseudo) {
       return identifier;
@@ -498,7 +498,7 @@
       'as'
     ];
     if (identifier.type.isBuiltIn &&
-        isOneOfOrEof(identifier.next, followingValues)) {
+        isOneOfOrEof(identifier.next!, followingValues)) {
       parser.reportRecoverableErrorWithToken(
           identifier, codes.templateBuiltInIdentifierInDeclaration);
     } else if (looksLikeStartOfNextTopLevelDeclaration(identifier) ||
@@ -532,7 +532,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       return identifier;
@@ -556,7 +556,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       checkAsyncAwaitYieldAsIdentifier(identifier, parser);
@@ -592,7 +592,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       checkAsyncAwaitYieldAsIdentifier(identifier, parser);
@@ -627,7 +627,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       checkAsyncAwaitYieldAsIdentifier(identifier, parser);
@@ -676,12 +676,12 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     const List<String> followingValues = const ['.', ';'];
 
     if (identifier.isIdentifier) {
-      Token next = identifier.next;
+      Token next = identifier.next!;
       if (!looksLikeStartOfNextTopLevelDeclaration(identifier) ||
           isOneOfOrEof(next, followingValues)) {
         return identifier;
@@ -720,7 +720,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       checkAsyncAwaitYieldAsIdentifier(identifier, parser);
@@ -765,7 +765,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       checkAsyncAwaitYieldAsIdentifier(identifier, parser);
@@ -812,7 +812,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       return identifier;
@@ -843,7 +843,7 @@
   Token ensureIdentifierPotentiallyRecovered(
       Token token, Parser parser, bool isRecovered) {
     // Fast path good case.
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       return identifier;
@@ -867,7 +867,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.isIdentifier) {
       checkAsyncAwaitYieldAsIdentifier(identifier, parser);
@@ -905,11 +905,11 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
 
     if (identifier.isIdentifier) {
-      Token next = identifier.next;
+      Token next = identifier.next!;
       if (!looksLikeStartOfNextTopLevelDeclaration(identifier) ||
           isOneOfOrEof(next, followingValues)) {
         return identifier;
@@ -946,11 +946,11 @@
   Token ensureIdentifierPotentiallyRecovered(
       Token token, Parser parser, bool isRecovered) {
     // Fast path good case.
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
 
     if (identifier.isIdentifier) {
-      Token next = identifier.next;
+      Token next = identifier.next!;
       if (!looksLikeStartOfNextTopLevelDeclaration(identifier) ||
           isOneOfOrEof(next, followingValues)) {
         return identifier;
@@ -976,7 +976,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.type.isPseudo) {
       if (optional('Function', identifier)) {
@@ -989,7 +989,7 @@
     // Recovery
     const List<String> followingValues = const ['(', '<', '=', ';'];
     if (identifier.type.isBuiltIn &&
-        isOneOfOrEof(identifier.next, followingValues)) {
+        isOneOfOrEof(identifier.next!, followingValues)) {
       parser.reportRecoverableErrorWithToken(
           identifier, codes.templateBuiltInIdentifierInDeclaration);
     } else if (looksLikeStartOfNextTopLevelDeclaration(identifier) ||
@@ -1015,7 +1015,7 @@
   Token ensureIdentifierPotentiallyRecovered(
       Token token, Parser parser, bool isRecovered) {
     // Fast path good case.
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.type.isPseudo) {
       if (optional('Function', identifier)) {
@@ -1057,7 +1057,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(next.kind != IDENTIFIER_TOKEN);
     if (isValidTypeReference(next)) {
       return next;
@@ -1082,7 +1082,7 @@
         next, const ['<', '>', ')', '[', ']', '[]', '{', '}', ',', ';'])) {
       // When in doubt, consume the token to ensure we make progress
       token = next;
-      next = token.next;
+      next = token.next!;
     }
     // Insert a synthetic identifier to satisfy listeners.
     return parser.rewriter.insertSyntheticIdentifier(token);
@@ -1097,7 +1097,7 @@
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
-    Token identifier = token.next;
+    Token identifier = token.next!;
     assert(identifier.kind != IDENTIFIER_TOKEN);
     if (identifier.type.isPseudo) {
       return identifier;
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
index c898b58..bb635b6 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
@@ -40,7 +40,7 @@
 /// Events starting with `handle` are used when isn't possible to have a begin
 /// event.
 class Listener implements UnescapeErrorListener {
-  Uri get uri => null;
+  Uri? get uri => null;
 
   void logEvent(String name) {}
 
@@ -51,7 +51,7 @@
   }
 
   /// Handle async modifiers `async`, `async*`, `sync`.
-  void handleAsyncModifier(Token asyncToken, Token starToken) {
+  void handleAsyncModifier(Token? asyncToken, Token? starToken) {
     logEvent("AsyncModifier");
   }
 
@@ -123,14 +123,14 @@
   /// (or extraneous modifiers in the case of recovery) preceding [name].
   ///
   /// At this point we have parsed the name and type parameter declarations.
-  void beginClassDeclaration(Token begin, Token abstractToken, Token name) {}
+  void beginClassDeclaration(Token begin, Token? abstractToken, Token name) {}
 
   /// Handle an extends clause in a class declaration. Substructures:
   /// - supertype (may be a mixin application)
   /// The typeCount is for error recovery: Invalid code might have more than one
   /// class specified in the extends clause. A parser error has already been
   /// issued.
-  void handleClassExtends(Token extendsKeyword, int typeCount) {
+  void handleClassExtends(Token? extendsKeyword, int typeCount) {
     logEvent("ClassExtends");
   }
 
@@ -138,7 +138,7 @@
   /// Substructures:
   /// - implemented types
   void handleClassOrMixinImplements(
-      Token implementsKeyword, int interfacesCount) {
+      Token? implementsKeyword, int interfacesCount) {
     logEvent("ClassImplements");
   }
 
@@ -151,7 +151,7 @@
   /// - with clause
   /// - implemented types
   /// - native clause
-  void handleClassHeader(Token begin, Token classKeyword, Token nativeToken) {
+  void handleClassHeader(Token begin, Token classKeyword, Token? nativeToken) {
     logEvent("ClassHeader");
   }
 
@@ -179,7 +179,7 @@
 
   /// Handle an on clause in a mixin declaration. Substructures:
   /// - implemented types
-  void handleMixinOn(Token onKeyword, int typeCount) {
+  void handleMixinOn(Token? onKeyword, int typeCount) {
     logEvent("MixinOn");
   }
 
@@ -229,7 +229,7 @@
   /// - type variables
   ///
   /// At this point we have parsed the name and type parameter declarations.
-  void beginExtensionDeclaration(Token extensionKeyword, Token name) {}
+  void beginExtensionDeclaration(Token extensionKeyword, Token? name) {}
 
   /// Handle the end of an extension methods declaration.  Substructures:
   /// - substructures from [beginExtensionDeclaration]
@@ -269,7 +269,7 @@
   void beginConstructorReference(Token start) {}
 
   void endConstructorReference(
-      Token start, Token periodBeforeName, Token endToken) {
+      Token start, Token? periodBeforeName, Token endToken) {
     logEvent("ConstructorReference");
   }
 
@@ -328,7 +328,7 @@
   /// Note that this is ended by [endClassFactoryMethod],
   /// [endMixinFactoryMethod] or [endExtensionFactoryMethod].
   void beginFactoryMethod(
-      Token lastConsumed, Token externalToken, Token constToken) {}
+      Token lastConsumed, Token? externalToken, Token? constToken) {}
 
   void endClassFactoryMethod(
       Token beginToken, Token factoryKeyword, Token endToken) {
@@ -347,15 +347,15 @@
     endClassFactoryMethod(beginToken, factoryKeyword, endToken);
   }
 
-  void beginFormalParameter(Token token, MemberKind kind, Token requiredToken,
-      Token covariantToken, Token varFinalOrConst) {}
+  void beginFormalParameter(Token token, MemberKind kind, Token? requiredToken,
+      Token? covariantToken, Token? varFinalOrConst) {}
 
   void endFormalParameter(
-      Token thisKeyword,
-      Token periodAfterThis,
+      Token? thisKeyword,
+      Token? periodAfterThis,
       Token nameToken,
-      Token initializerStart,
-      Token initializerEnd,
+      Token? initializerStart,
+      Token? initializerEnd,
       FormalParameterKind kind,
       MemberKind memberKind) {
     logEvent("FormalParameter");
@@ -380,12 +380,12 @@
   ///
   /// Started by [beginFields].
   void endClassFields(
-      Token abstractToken,
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       int count,
       Token beginToken,
       Token endToken) {
@@ -400,12 +400,12 @@
   ///
   /// Started by [beginFields].
   void endMixinFields(
-      Token abstractToken,
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       int count,
       Token beginToken,
       Token endToken) {
@@ -422,12 +422,12 @@
   ///
   /// Started by [beginFields].
   void endExtensionFields(
-      Token abstractToken,
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       int count,
       Token beginToken,
       Token endToken) {
@@ -477,7 +477,7 @@
   /// Marks the end of parsing the control structure of a for-in statement
   /// or for control flow entry up to and including the closing parenthesis.
   /// `for` `(` (type)? identifier `in` iterator `)`
-  void handleForInLoopParts(Token awaitToken, Token forToken,
+  void handleForInLoopParts(Token? awaitToken, Token forToken,
       Token leftParenthesis, Token inKeyword) {}
 
   // One of the two possible corresponding end events for [beginForStatement].
@@ -594,7 +594,7 @@
   /// - Alias type variables
   /// - Type (FunctionTypeAnnotation)
   void endFunctionTypeAlias(
-      Token typedefKeyword, Token equals, Token endToken) {
+      Token typedefKeyword, Token? equals, Token endToken) {
     logEvent("FunctionTypeAlias");
   }
 
@@ -616,7 +616,7 @@
   ///
   /// At this point we have parsed the name and type parameter declarations.
   void beginNamedMixinApplication(
-      Token begin, Token abstractToken, Token name) {}
+      Token begin, Token? abstractToken, Token name) {}
 
   /// Handle a named mixin application with clause (e.g. "A with B, C").
   /// Substructures:
@@ -640,7 +640,7 @@
   /// declaration, each implemented type is listed separately on the stack, and
   /// the number of implemented types is passed as a parameter.
   void endNamedMixinApplication(Token begin, Token classKeyword, Token equals,
-      Token implementsKeyword, Token endToken) {
+      Token? implementsKeyword, Token endToken) {
     logEvent("NamedMixinApplication");
   }
 
@@ -664,7 +664,7 @@
 
   void beginIfStatement(Token token) {}
 
-  void endIfStatement(Token ifToken, Token elseToken) {
+  void endIfStatement(Token ifToken, Token? elseToken) {
     logEvent("IfStatement");
   }
 
@@ -686,7 +686,7 @@
   /// depending upon whether [deferredKeyword] and [asKeyword]
   /// are not `null` respectively. Substructures:
   /// - prefix identifier (only if asKeyword != null)
-  void handleImportPrefix(Token deferredKeyword, Token asKeyword) {
+  void handleImportPrefix(Token? deferredKeyword, Token? asKeyword) {
     logEvent("ImportPrefix");
   }
 
@@ -696,7 +696,7 @@
   /// - conditional uris
   /// - prefix identifier
   /// - combinators
-  void endImport(Token importKeyword, Token semicolon) {
+  void endImport(Token importKeyword, Token? semicolon) {
     logEvent("Import");
   }
 
@@ -707,7 +707,7 @@
   /// - conditional uris
   /// - prefix identifier
   /// - combinators
-  void handleRecoverImport(Token semicolon) {
+  void handleRecoverImport(Token? semicolon) {
     logEvent("ImportRecovery");
   }
 
@@ -723,7 +723,7 @@
   /// - Dotted name
   /// - Condition (literal string; only if [equalSign] != null)
   /// - URI (literal string)
-  void endConditionalUri(Token ifKeyword, Token leftParen, Token equalSign) {
+  void endConditionalUri(Token ifKeyword, Token leftParen, Token? equalSign) {
     logEvent("ConditionalUri");
   }
 
@@ -831,7 +831,7 @@
 
   void beginLiteralString(Token token) {}
 
-  void handleInterpolationExpression(Token leftBracket, Token rightBracket) {}
+  void handleInterpolationExpression(Token leftBracket, Token? rightBracket) {}
 
   void endLiteralString(int interpolationCount, Token endToken) {
     logEvent("LiteralString");
@@ -870,8 +870,13 @@
   /// Note that this is ended with [endClassConstructor], [endClassMethod],
   /// [endExtensionConstructor], [endExtensionMethod], [endMixinConstructor] or
   /// [endMixinMethod].
-  void beginMethod(Token externalToken, Token staticToken, Token covariantToken,
-      Token varFinalOrConst, Token getOrSet, Token name) {}
+  void beginMethod(
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? varFinalOrConst,
+      Token? getOrSet,
+      Token name) {}
 
   /// Handle the end of a class method declaration.  Substructures:
   /// - metadata
@@ -882,8 +887,8 @@
   /// - initializers
   /// - async marker
   /// - body
-  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
+  void endClassMethod(Token? getOrSet, Token beginToken, Token beginParam,
+      Token? beginInitializers, Token endToken) {
     logEvent("ClassMethod");
   }
 
@@ -896,8 +901,8 @@
   /// - initializers
   /// - async marker
   /// - body
-  void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
+  void endMixinMethod(Token? getOrSet, Token beginToken, Token beginParam,
+      Token? beginInitializers, Token endToken) {
     // TODO(danrubel): push implementation into subclasses
     endClassMethod(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
@@ -912,8 +917,8 @@
   /// - initializers
   /// - async marker
   /// - body
-  void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
+  void endExtensionMethod(Token? getOrSet, Token beginToken, Token beginParam,
+      Token? beginInitializers, Token endToken) {
     // TODO(danrubel): push implementation into subclasses
     endClassMethod(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
@@ -928,8 +933,8 @@
   /// - initializers
   /// - async marker
   /// - body
-  void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
+  void endClassConstructor(Token? getOrSet, Token beginToken, Token beginParam,
+      Token? beginInitializers, Token endToken) {
     // TODO(danrubel): push implementation into subclasses
     endClassMethod(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
@@ -944,8 +949,8 @@
   /// - initializers
   /// - async marker
   /// - body
-  void endMixinConstructor(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
+  void endMixinConstructor(Token? getOrSet, Token beginToken, Token beginParam,
+      Token? beginInitializers, Token endToken) {
     // TODO(danrubel): push implementation into subclasses
     endClassMethod(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
@@ -960,8 +965,8 @@
   /// - initializers
   /// - async marker
   /// - body
-  void endExtensionConstructor(Token getOrSet, Token beginToken,
-      Token beginParam, Token beginInitializers, Token endToken) {
+  void endExtensionConstructor(Token? getOrSet, Token beginToken,
+      Token beginParam, Token? beginInitializers, Token endToken) {
     // TODO(danrubel): push implementation into subclasses
     endClassMethod(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
@@ -980,7 +985,7 @@
   /// - Type arguments
   /// - Constructor name (only if [periodBeforeName] is not `null`)
   /// - Arguments
-  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+  void endMetadata(Token beginToken, Token? periodBeforeName, Token endToken) {
     logEvent("Metadata");
   }
 
@@ -1048,7 +1053,7 @@
 
   /// This method is invoked when parser finishes parsing the corresponding
   /// expression of the expression function body.
-  void handleExpressionFunctionBody(Token arrowToken, Token endToken) {
+  void handleExpressionFunctionBody(Token arrowToken, Token? endToken) {
     logEvent("ExpressionFunctionBody");
   }
 
@@ -1146,18 +1151,18 @@
   ///
   /// Started by [beginFields].
   void endTopLevelFields(
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       int count,
       Token beginToken,
       Token endToken) {
     logEvent("TopLevelFields");
   }
 
-  void beginTopLevelMethod(Token lastConsumed, Token externalToken) {}
+  void beginTopLevelMethod(Token lastConsumed, Token? externalToken) {}
 
   /// Handle the end of a top level method.  Substructures:
   /// - metadata
@@ -1168,7 +1173,7 @@
   /// - formal parameters
   /// - async marker
   /// - body
-  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
+  void endTopLevelMethod(Token beginToken, Token? getOrSet, Token endToken) {
     logEvent("TopLevelMethod");
   }
 
@@ -1184,7 +1189,7 @@
     logEvent("CatchClause");
   }
 
-  void handleCatchBlock(Token onKeyword, Token catchKeyword, Token comma) {
+  void handleCatchBlock(Token? onKeyword, Token? catchKeyword, Token? comma) {
     logEvent("CatchBlock");
   }
 
@@ -1192,11 +1197,12 @@
     logEvent("FinallyBlock");
   }
 
-  void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
+  void endTryStatement(
+      int catchCount, Token tryKeyword, Token? finallyKeyword) {
     logEvent("TryStatement");
   }
 
-  void handleType(Token beginToken, Token questionMark) {
+  void handleType(Token beginToken, Token? questionMark) {
     logEvent("Type");
   }
 
@@ -1218,7 +1224,7 @@
   /// - Type variables
   /// - Return type
   /// - Formal parameters
-  void endFunctionType(Token functionToken, Token questionMark) {
+  void endFunctionType(Token functionToken, Token? questionMark) {
     logEvent("FunctionType");
   }
 
@@ -1258,7 +1264,7 @@
   ///
   /// See [beginTypeVariable] for additional substructures.
   void endTypeVariable(
-      Token token, int index, Token extendsOrSuper, Token variance) {
+      Token token, int index, Token? extendsOrSuper, Token? variance) {
     logEvent("TypeVariable");
   }
 
@@ -1268,7 +1274,7 @@
     logEvent("TypeVariables");
   }
 
-  void reportVarianceModifierNotEnabled(Token variance) {
+  void reportVarianceModifierNotEnabled(Token? variance) {
     if (variance != null) {
       handleRecoverableError(
           templateExperimentNotEnabled.withArguments('variance', '2.9'),
@@ -1293,9 +1299,9 @@
   /// - Metadata
   /// - Type
   void beginVariablesDeclaration(
-      Token token, Token lateToken, Token varFinalOrConst) {}
+      Token token, Token? lateToken, Token? varFinalOrConst) {}
 
-  void endVariablesDeclaration(int count, Token endToken) {
+  void endVariablesDeclaration(int count, Token? endToken) {
     logEvent("VariablesDeclaration");
   }
 
@@ -1356,7 +1362,7 @@
 
   /// Called before parsing a "for" control flow list, set, or map entry.
   /// Ended by either [endForControlFlow] or [endForInControlFlow].
-  void beginForControlFlow(Token awaitToken, Token forToken) {}
+  void beginForControlFlow(Token? awaitToken, Token forToken) {}
 
   /// Called after parsing a "for" control flow list, set, or map entry.
   /// One of the two possible corresponding end events for
@@ -1422,7 +1428,7 @@
   /// - type variables
   /// - return type
   /// - formal parameters
-  void endFunctionTypedFormalParameter(Token nameToken, Token question) {
+  void endFunctionTypedFormalParameter(Token nameToken, Token? question) {
     logEvent("FunctionTypedFormalParameter");
   }
 
@@ -1434,7 +1440,7 @@
   }
 
   void handleIndexedExpression(
-      Token question, Token openSquareBracket, Token closeSquareBracket) {
+      Token? question, Token openSquareBracket, Token closeSquareBracket) {
     logEvent("IndexedExpression");
   }
 
@@ -1444,7 +1450,7 @@
     logEvent("IsOperatorType");
   }
 
-  void handleIsOperator(Token isOperator, Token not) {
+  void handleIsOperator(Token isOperator, Token? not) {
     logEvent("IsOperator");
   }
 
@@ -1469,7 +1475,7 @@
   void beginAssert(Token assertKeyword, Assert kind) {}
 
   void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis,
-      Token commaToken, Token semicolonToken) {
+      Token? commaToken, Token semicolonToken) {
     logEvent("Assert");
   }
 
@@ -1488,14 +1494,14 @@
   }
 
   void handleLiteralList(
-      int count, Token leftBracket, Token constKeyword, Token rightBracket) {
+      int count, Token leftBracket, Token? constKeyword, Token rightBracket) {
     logEvent("LiteralList");
   }
 
   void handleLiteralSetOrMap(
     int count,
     Token leftBrace,
-    Token constKeyword,
+    Token? constKeyword,
     Token rightBrace,
     // TODO(danrubel): hasSetEntry parameter exists for replicating existing
     // behavior and will be removed once unified collection has been enabled
@@ -1595,8 +1601,8 @@
   void endSwitchCase(
       int labelCount,
       int expressionCount,
-      Token defaultKeyword,
-      Token colonAfterDefault,
+      Token? defaultKeyword,
+      Token? colonAfterDefault,
       int statementCount,
       Token firstToken,
       Token endToken) {
@@ -1648,13 +1654,13 @@
 
   /// One of the two possible corresponding end events for
   /// [beginYieldStatement].
-  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
+  void endYieldStatement(Token yieldToken, Token? starToken, Token endToken) {
     logEvent("YieldStatement");
   }
 
   /// One of the two possible corresponding end events for
   /// [beginYieldStatement].
-  void endInvalidYieldStatement(Token beginToken, Token starToken,
+  void endInvalidYieldStatement(Token beginToken, Token? starToken,
       Token endToken, MessageCode errorCode) {
     logEvent("InvalidYieldStatement");
   }
@@ -1712,7 +1718,7 @@
   /// This event is generated by the parser when the parser's
   /// `parseOneCommentReference` method is called.
   void handleCommentReference(
-      Token newKeyword, Token prefix, Token period, Token token) {}
+      Token? newKeyword, Token? prefix, Token? period, Token token) {}
 
   /// This event is generated by the parser when the parser's
   /// `parseOneCommentReference` method is called.
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info.dart b/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info.dart
index 35221fd..8b5b93a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info.dart
@@ -50,16 +50,16 @@
   }
 
   /// Returns the next step when parsing an entry or `null` if none.
-  LiteralEntryInfo computeNext(Token token) => null;
+  LiteralEntryInfo? computeNext(Token token) => null;
 }
 
 /// Compute the [LiteralEntryInfo] for the literal list, map, or set entry.
 LiteralEntryInfo computeLiteralEntry(Token token) {
-  Token next = token.next;
+  Token next = token.next!;
   if (optional('if', next)) {
     return ifCondition;
   } else if (optional('for', next) ||
-      (optional('await', next) && optional('for', next.next))) {
+      (optional('await', next) && optional('for', next.next!))) {
     return new ForCondition();
   } else if (optional('...', next) || optional('...?', next)) {
     return spreadOperator;
@@ -75,4 +75,4 @@
     optional('...?', token) ||
     optional('if', token) ||
     optional('for', token) ||
-    (optional('await', token) && optional('for', token.next));
+    (optional('await', token) && optional('for', token.next!));
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart
index 9e559f1..309bf3e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart
@@ -17,27 +17,27 @@
 
 /// The first step when processing a `for` control flow collection entry.
 class ForCondition extends LiteralEntryInfo {
-  bool inStyle;
+  late bool inStyle;
 
   ForCondition() : super(false, 0);
 
   @override
   Token parse(Token token, Parser parser) {
-    Token next = token.next;
-    Token awaitToken;
+    Token next = token.next!;
+    Token? awaitToken;
     if (optional('await', next)) {
       awaitToken = token = next;
-      next = token.next;
+      next = token.next!;
     }
     final Token forToken = next;
     assert(optional('for', forToken));
     parser.listener.beginForControlFlow(awaitToken, forToken);
 
     token = parser.parseForLoopPartsStart(awaitToken, forToken);
-    Token identifier = token.next;
+    Token identifier = token.next!;
     token = parser.parseForLoopPartsMid(token, awaitToken, forToken);
 
-    if (optional('in', token.next) || optional(':', token.next)) {
+    if (optional('in', token.next!) || optional(':', token.next!)) {
       // Process `for ( ... in ... )`
       inStyle = true;
       token = parser.parseForInLoopPartsRest(
@@ -52,9 +52,9 @@
 
   @override
   LiteralEntryInfo computeNext(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('for', next) ||
-        (optional('await', next) && optional('for', next.next))) {
+        (optional('await', next) && optional('for', next.next!))) {
       return new Nested(
         new ForCondition(),
         inStyle ? const ForInComplete() : const ForComplete(),
@@ -141,7 +141,7 @@
 
   @override
   Token parse(Token token, Parser parser) {
-    final Token ifToken = token.next;
+    final Token ifToken = token.next!;
     assert(optional('if', ifToken));
     parser.listener.beginIfControlFlow(ifToken);
     Token result = parser.ensureParenthesizedCondition(ifToken);
@@ -151,9 +151,9 @@
 
   @override
   LiteralEntryInfo computeNext(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('for', next) ||
-        (optional('await', next) && optional('for', next.next))) {
+        (optional('await', next) && optional('for', next.next!))) {
       return new Nested(new ForCondition(), const IfComplete());
     } else if (optional('if', next)) {
       return new Nested(ifCondition, const IfComplete());
@@ -187,15 +187,15 @@
 
   @override
   Token parse(Token token, Parser parser) {
-    if (!optional('else', token.next)) {
+    if (!optional('else', token.next!)) {
       parser.listener.endIfControlFlow(token);
     }
     return token;
   }
 
   @override
-  LiteralEntryInfo computeNext(Token token) {
-    return optional('else', token.next) ? const IfElse() : null;
+  LiteralEntryInfo? computeNext(Token token) {
+    return optional('else', token.next!) ? const IfElse() : null;
   }
 }
 
@@ -205,7 +205,7 @@
 
   @override
   Token parse(Token token, Parser parser) {
-    Token elseToken = token.next;
+    Token elseToken = token.next!;
     assert(optional('else', elseToken));
     parser.listener.handleElseControlFlow(elseToken);
     return elseToken;
@@ -214,9 +214,9 @@
   @override
   LiteralEntryInfo computeNext(Token token) {
     assert(optional('else', token));
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('for', next) ||
-        (optional('await', next) && optional('for', next.next))) {
+        (optional('await', next) && optional('for', next.next!))) {
       return new Nested(new ForCondition(), const IfElseComplete());
     } else if (optional('if', next)) {
       return new Nested(ifCondition, const IfElseComplete());
@@ -261,7 +261,7 @@
 
   @override
   Token parse(Token token, Parser parser) {
-    final Token operator = token.next;
+    final Token operator = token.next!;
     assert(optional('...', operator) || optional('...?', operator));
     token = parser.parseExpression(operator);
     parser.listener.handleSpreadExpression(operator);
@@ -270,20 +270,20 @@
 }
 
 class Nested extends LiteralEntryInfo {
-  LiteralEntryInfo nestedStep;
+  LiteralEntryInfo? nestedStep;
   final LiteralEntryInfo lastStep;
 
   Nested(this.nestedStep, this.lastStep) : super(false, 0);
 
   @override
-  bool get hasEntry => nestedStep.hasEntry;
+  bool get hasEntry => nestedStep!.hasEntry;
 
   @override
-  Token parse(Token token, Parser parser) => nestedStep.parse(token, parser);
+  Token parse(Token token, Parser parser) => nestedStep!.parse(token, parser);
 
   @override
   LiteralEntryInfo computeNext(Token token) {
-    nestedStep = nestedStep.computeNext(token);
+    nestedStep = nestedStep!.computeNext(token);
     return nestedStep != null ? this : lastStep;
   }
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/modifier_context.dart b/pkg/_fe_analyzer_shared/lib/src/parser/modifier_context.dart
index 3ef7898..a062b38 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/modifier_context.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/modifier_context.dart
@@ -23,8 +23,8 @@
     //   external() => true;
     // and in
     //   for (final external in list) { }
-    Token next = token.next;
-    Keyword keyword = next.keyword;
+    Token next = token.next!;
+    Keyword? keyword = next.keyword;
     if (keyword == null && !next.isIdentifier || keyword == Keyword.IN) {
       return false;
     }
@@ -36,15 +36,15 @@
 /// can occur, but does not call handleModifier or handleModifiers.
 class ModifierRecoveryContext {
   final Parser parser;
-  Token abstractToken;
-  Token constToken;
-  Token covariantToken;
-  Token externalToken;
-  Token finalToken;
-  Token lateToken;
-  Token requiredToken;
-  Token staticToken;
-  Token varToken;
+  Token? abstractToken;
+  Token? constToken;
+  Token? covariantToken;
+  Token? externalToken;
+  Token? finalToken;
+  Token? lateToken;
+  Token? requiredToken;
+  Token? staticToken;
+  Token? varToken;
 
   // Set `true` when parsing modifiers after the `factory` token.
   bool afterFactory = false;
@@ -54,7 +54,7 @@
 
   ModifierRecoveryContext(this.parser);
 
-  set staticOrCovariant(Token staticOrCovariant) {
+  set staticOrCovariant(Token? staticOrCovariant) {
     if (staticOrCovariant == null) {
       covariantToken = null;
       staticToken = null;
@@ -70,9 +70,9 @@
     }
   }
 
-  Token get varFinalOrConst => varToken ?? finalToken ?? constToken;
+  Token? get varFinalOrConst => varToken ?? finalToken ?? constToken;
 
-  set varFinalOrConst(Token varFinalOrConst) {
+  set varFinalOrConst(Token? varFinalOrConst) {
     if (varFinalOrConst == null) {
       varToken = null;
       finalToken = null;
@@ -121,7 +121,7 @@
     } else if (memberKind == MemberKind.GeneralizedFunctionType) {
       if (varFinalOrConst != null) {
         parser.reportRecoverableError(
-            varFinalOrConst, codes.messageFunctionTypedParameterVar);
+            varFinalOrConst!, codes.messageFunctionTypedParameterVar);
       }
     }
     reportExtraneousModifier(abstractToken);
@@ -137,7 +137,7 @@
     token = parseModifiers(token);
     if (abstractToken != null) {
       parser.reportRecoverableError(
-          abstractToken, codes.messageAbstractClassMember);
+          abstractToken!, codes.messageAbstractClassMember);
     }
     reportExtraneousModifier(lateToken);
     reportExtraneousModifier(requiredToken);
@@ -178,9 +178,9 @@
   /// in that order, and the others ignored.
   Token parseModifiers(Token token) {
     // Process invalid and out-of-order modifiers
-    Token next = token.next;
+    Token next = token.next!;
     while (true) {
-      final String value = next.stringValue;
+      final String? value = next.stringValue;
       if (isModifier(next)) {
         if (identical('abstract', value)) {
           token = parseAbstract(token);
@@ -210,21 +210,21 @@
       } else {
         break;
       }
-      next = token.next;
+      next = token.next!;
     }
     return token;
   }
 
   Token parseAbstract(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('abstract', next));
     if (abstractToken == null) {
       abstractToken = next;
 
       if (varFinalOrConst != null) {
-        reportModifierOutOfOrder(next, varFinalOrConst.lexeme);
+        reportModifierOutOfOrder(next, varFinalOrConst!.lexeme);
       } else if (covariantToken != null) {
-        reportModifierOutOfOrder(next, covariantToken.lexeme);
+        reportModifierOutOfOrder(next, covariantToken!.lexeme);
       }
       return next;
     }
@@ -236,7 +236,7 @@
   }
 
   Token parseConst(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('const', next));
     if (varFinalOrConst == null && covariantToken == null) {
       constToken = next;
@@ -244,7 +244,7 @@
       if (afterFactory) {
         reportModifierOutOfOrder(next, 'factory');
       } else if (lateToken != null) {
-        reportConflictingModifiers(next, lateToken);
+        reportConflictingModifiers(next, lateToken!);
       }
       return next;
     }
@@ -254,11 +254,11 @@
       parser.reportRecoverableErrorWithToken(
           next, codes.templateDuplicatedModifier);
     } else if (covariantToken != null) {
-      reportConflictingModifiers(next, covariantToken);
+      reportConflictingModifiers(next, covariantToken!);
     } else if (finalToken != null) {
       parser.reportRecoverableError(next, codes.messageConstAndFinal);
     } else if (varToken != null) {
-      reportConflictingModifiers(next, varToken);
+      reportConflictingModifiers(next, varToken!);
     } else {
       throw 'Internal Error: Unexpected varFinalOrConst: $varFinalOrConst';
     }
@@ -266,7 +266,7 @@
   }
 
   Token parseCovariant(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('covariant', next));
     if (constToken == null &&
         covariantToken == null &&
@@ -275,11 +275,11 @@
       covariantToken = next;
 
       if (varToken != null) {
-        reportModifierOutOfOrder(next, varToken.lexeme);
+        reportModifierOutOfOrder(next, varToken!.lexeme);
       } else if (finalToken != null) {
-        reportModifierOutOfOrder(next, finalToken.lexeme);
+        reportModifierOutOfOrder(next, finalToken!.lexeme);
       } else if (lateToken != null) {
-        reportModifierOutOfOrder(next, lateToken.lexeme);
+        reportModifierOutOfOrder(next, lateToken!.lexeme);
       }
       return next;
     }
@@ -291,7 +291,7 @@
     } else if (afterFactory) {
       reportExtraneousModifier(next);
     } else if (constToken != null) {
-      reportConflictingModifiers(next, constToken);
+      reportConflictingModifiers(next, constToken!);
     } else if (staticToken != null) {
       parser.reportRecoverableError(next, codes.messageCovariantAndStatic);
     } else {
@@ -301,7 +301,7 @@
   }
 
   Token parseExternal(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('external', next));
     if (externalToken == null) {
       externalToken = next;
@@ -309,15 +309,15 @@
       if (afterFactory) {
         reportModifierOutOfOrder(next, 'factory');
       } else if (constToken != null) {
-        reportModifierOutOfOrder(next, constToken.lexeme);
+        reportModifierOutOfOrder(next, constToken!.lexeme);
       } else if (staticToken != null) {
-        reportModifierOutOfOrder(next, staticToken.lexeme);
+        reportModifierOutOfOrder(next, staticToken!.lexeme);
       } else if (lateToken != null) {
-        reportModifierOutOfOrder(next, lateToken.lexeme);
+        reportModifierOutOfOrder(next, lateToken!.lexeme);
       } else if (varFinalOrConst != null) {
-        reportModifierOutOfOrder(next, varFinalOrConst.lexeme);
+        reportModifierOutOfOrder(next, varFinalOrConst!.lexeme);
       } else if (covariantToken != null) {
-        reportModifierOutOfOrder(next, covariantToken.lexeme);
+        reportModifierOutOfOrder(next, covariantToken!.lexeme);
       }
       return next;
     }
@@ -329,7 +329,7 @@
   }
 
   Token parseFinal(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('final', next));
     if (varFinalOrConst == null && !afterFactory) {
       finalToken = next;
@@ -347,7 +347,7 @@
     } else if (varToken != null) {
       parser.reportRecoverableError(next, codes.messageFinalAndVar);
     } else if (lateToken != null) {
-      reportModifierOutOfOrder(next, lateToken.lexeme);
+      reportModifierOutOfOrder(next, lateToken!.lexeme);
     } else {
       throw 'Internal Error: Unexpected varFinalOrConst: $varFinalOrConst';
     }
@@ -355,17 +355,17 @@
   }
 
   Token parseLate(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('late', next));
     if (lateToken == null) {
       lateToken = next;
 
       if (constToken != null) {
-        reportConflictingModifiers(next, constToken);
+        reportConflictingModifiers(next, constToken!);
       } else if (varToken != null) {
-        reportModifierOutOfOrder(next, varToken.lexeme);
+        reportModifierOutOfOrder(next, varToken!.lexeme);
       } else if (finalToken != null) {
-        reportModifierOutOfOrder(next, finalToken.lexeme);
+        reportModifierOutOfOrder(next, finalToken!.lexeme);
       }
       return next;
     }
@@ -377,19 +377,19 @@
   }
 
   Token parseRequired(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('required', next));
     if (requiredToken == null) {
       requiredToken = next;
 
       if (constToken != null) {
-        reportModifierOutOfOrder(requiredToken, constToken.lexeme);
+        reportModifierOutOfOrder(requiredToken!, constToken!.lexeme);
       } else if (covariantToken != null) {
-        reportModifierOutOfOrder(requiredToken, covariantToken.lexeme);
+        reportModifierOutOfOrder(requiredToken!, covariantToken!.lexeme);
       } else if (finalToken != null) {
-        reportModifierOutOfOrder(requiredToken, finalToken.lexeme);
+        reportModifierOutOfOrder(requiredToken!, finalToken!.lexeme);
       } else if (varToken != null) {
-        reportModifierOutOfOrder(requiredToken, varToken.lexeme);
+        reportModifierOutOfOrder(requiredToken!, varToken!.lexeme);
       }
       return next;
     }
@@ -401,19 +401,19 @@
   }
 
   Token parseStatic(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('static', next));
     if (covariantToken == null && staticToken == null && !afterFactory) {
       staticToken = next;
 
       if (constToken != null) {
-        reportModifierOutOfOrder(next, constToken.lexeme);
+        reportModifierOutOfOrder(next, constToken!.lexeme);
       } else if (finalToken != null) {
-        reportModifierOutOfOrder(next, finalToken.lexeme);
+        reportModifierOutOfOrder(next, finalToken!.lexeme);
       } else if (varToken != null) {
-        reportModifierOutOfOrder(next, varToken.lexeme);
+        reportModifierOutOfOrder(next, varToken!.lexeme);
       } else if (lateToken != null) {
-        reportModifierOutOfOrder(next, lateToken.lexeme);
+        reportModifierOutOfOrder(next, lateToken!.lexeme);
       }
       return next;
     }
@@ -433,7 +433,7 @@
   }
 
   Token parseVar(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('var', next));
     if (varFinalOrConst == null && !afterFactory) {
       varToken = next;
@@ -447,7 +447,7 @@
     } else if (afterFactory) {
       reportExtraneousModifier(next);
     } else if (constToken != null) {
-      reportConflictingModifiers(next, constToken);
+      reportConflictingModifiers(next, constToken!);
     } else if (finalToken != null) {
       parser.reportRecoverableError(next, codes.messageFinalAndVar);
     } else {
@@ -463,14 +463,14 @@
             .withArguments(modifier.lexeme, earlierModifier.lexeme));
   }
 
-  void reportExtraneousModifier(Token modifier) {
+  void reportExtraneousModifier(Token? modifier) {
     if (modifier != null) {
       parser.reportRecoverableErrorWithToken(
           modifier, codes.templateExtraneousModifier);
     }
   }
 
-  void reportExtraneousModifierInExtension(Token modifier) {
+  void reportExtraneousModifierInExtension(Token? modifier) {
     if (modifier != null) {
       parser.reportRecoverableErrorWithToken(
           modifier, codes.templateExtraneousModifierInExtension);
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
index 5754bf3..746d7ef 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -269,7 +269,7 @@
 class Parser {
   Listener listener;
 
-  Uri get uri => listener.uri;
+  Uri? get uri => listener.uri;
 
   bool mayParseFunctionExpressions = true;
 
@@ -291,14 +291,14 @@
 
   /// A rewriter for inserting synthetic tokens.
   /// Access using [rewriter] for lazy initialization.
-  TokenStreamRewriter cachedRewriter;
+  TokenStreamRewriter? cachedRewriter;
 
   TokenStreamRewriter get rewriter {
-    cachedRewriter ??= new TokenStreamRewriterImpl();
-    return cachedRewriter;
+    return cachedRewriter ??= new TokenStreamRewriterImpl();
   }
 
-  Parser(this.listener);
+  Parser(this.listener)
+      : assert(listener != null); // ignore:unnecessary_null_comparison
 
   bool get inGenerator {
     return asyncState == AsyncModifier.AsyncStar ||
@@ -348,30 +348,30 @@
     int count = 0;
     DirectiveContext directiveState = new DirectiveContext();
     token = syntheticPreviousToken(token);
-    if (identical(token.next.type, TokenType.SCRIPT_TAG)) {
-      directiveState?.checkScriptTag(this, token.next);
+    if (identical(token.next!.type, TokenType.SCRIPT_TAG)) {
+      directiveState.checkScriptTag(this, token.next!);
       token = parseScript(token);
     }
-    while (!token.next.isEof) {
-      final Token start = token.next;
+    while (!token.next!.isEof) {
+      final Token start = token.next!;
       token = parseTopLevelDeclarationImpl(token, directiveState);
-      listener.endTopLevelDeclaration(token.next);
+      listener.endTopLevelDeclaration(token.next!);
       count++;
-      if (start == token.next) {
+      if (start == token.next!) {
         // Recovery:
         // If progress has not been made reaching the end of the token stream,
         // then report an error and skip the current token.
-        token = token.next;
+        token = token.next!;
         listener.beginMetadataStar(token);
         listener.endMetadataStar(/* count = */ 0);
         reportRecoverableErrorWithToken(
             token, codes.templateExpectedDeclaration);
         listener.handleInvalidTopLevelDeclaration(token);
-        listener.endTopLevelDeclaration(token.next);
+        listener.endTopLevelDeclaration(token.next!);
         count++;
       }
     }
-    token = token.next;
+    token = token.next!;
     reportAllErrorTokens(errorToken);
     listener.endCompilationUnit(count, token);
     // Clear fields that could lead to memory leak.
@@ -394,9 +394,9 @@
     int count = 0;
     DirectiveContext directiveState = new DirectiveContext();
     token = syntheticPreviousToken(token);
-    while (!token.next.isEof) {
-      final Token start = token.next;
-      final String nextValue = start.next.stringValue;
+    while (!token.next!.isEof) {
+      final Token start = token.next!;
+      final String? nextValue = start.next!.stringValue;
 
       // If a built-in keyword is being used as function name, then stop.
       if (identical(nextValue, '.') ||
@@ -405,21 +405,21 @@
         break;
       }
 
-      if (identical(token.next.type, TokenType.SCRIPT_TAG)) {
-        directiveState?.checkScriptTag(this, token.next);
+      if (identical(token.next!.type, TokenType.SCRIPT_TAG)) {
+        directiveState.checkScriptTag(this, token.next!);
         token = parseScript(token);
       } else {
         token = parseMetadataStar(token);
-        Token keyword = token.next;
-        final String value = keyword.stringValue;
+        Token keyword = token.next!;
+        final String? value = keyword.stringValue;
         if (identical(value, 'import')) {
-          directiveState?.checkImport(this, keyword);
+          directiveState.checkImport(this, keyword);
           token = parseImport(keyword);
         } else if (identical(value, 'export')) {
-          directiveState?.checkExport(this, keyword);
+          directiveState.checkExport(this, keyword);
           token = parseExport(keyword);
         } else if (identical(value, 'library')) {
-          directiveState?.checkLibrary(this, keyword);
+          directiveState.checkLibrary(this, keyword);
           token = parseLibraryName(keyword);
         } else if (identical(value, 'part')) {
           token = parsePartOrPartOf(keyword, directiveState);
@@ -431,9 +431,9 @@
           break;
         }
       }
-      listener.endTopLevelDeclaration(token.next);
+      listener.endTopLevelDeclaration(token.next!);
     }
-    token = token.next;
+    token = token.next!;
     listener.endCompilationUnit(count, token);
     // Clear fields that could lead to memory leak.
     cachedRewriter = null;
@@ -449,7 +449,7 @@
   Token parseTopLevelDeclaration(Token token) {
     token = parseTopLevelDeclarationImpl(
             syntheticPreviousToken(token), /* directiveState = */ null)
-        .next;
+        .next!;
     listener.endTopLevelDeclaration(token);
     return token;
   }
@@ -470,9 +470,9 @@
   /// ;
   /// ```
   Token parseTopLevelDeclarationImpl(
-      Token token, DirectiveContext directiveState) {
+      Token token, DirectiveContext? directiveState) {
     token = parseMetadataStar(token);
-    Token next = token.next;
+    Token next = token.next!;
     if (next.isTopLevelKeyword) {
       return parseTopLevelKeywordDeclaration(token, next, directiveState);
     }
@@ -484,15 +484,15 @@
           ((optional('const', next) || optional('final', next)) &&
               // Ignore `const class` and `final class` so that it is reported
               // below as an invalid modifier on a class.
-              !optional('class', next.next))) {
+              !optional('class', next.next!))) {
         directiveState?.checkDeclaration();
         return parseTopLevelMemberImpl(token);
       }
-      while (token.next.isModifier) {
-        token = token.next;
+      while (token.next!.isModifier) {
+        token = token.next!;
       }
     }
-    next = token.next;
+    next = token.next!;
     if (next.isTopLevelKeyword) {
       return parseTopLevelKeywordDeclaration(start, next, directiveState);
     } else if (next.isKeywordOrIdentifier) {
@@ -506,7 +506,7 @@
       return parseTopLevelMemberImpl(start);
     }
     // Recovery
-    if (next.isOperator && optional('(', next.next)) {
+    if (next.isOperator && optional('(', next.next!)) {
       // This appears to be a top level operator declaration, which is invalid.
       reportRecoverableError(next, codes.messageTopLevelOperator);
       // Insert a synthetic identifier
@@ -522,8 +522,8 @@
 
   /// Parse the modifiers before the `class` keyword.
   /// Return the first `abstract` modifier or `null` if not found.
-  Token parseClassDeclarationModifiers(Token start, Token keyword) {
-    Token modifier = start.next;
+  Token? parseClassDeclarationModifiers(Token start, Token keyword) {
+    Token modifier = start.next!;
     while (modifier != keyword) {
       if (optional('abstract', modifier)) {
         parseTopLevelKeywordModifiers(modifier, keyword);
@@ -532,18 +532,18 @@
         // Recovery
         reportTopLevelModifierError(modifier, keyword);
       }
-      modifier = modifier.next;
+      modifier = modifier.next!;
     }
     return null;
   }
 
   /// Report errors on any modifiers before the specified keyword.
   void parseTopLevelKeywordModifiers(Token start, Token keyword) {
-    Token modifier = start.next;
+    Token modifier = start.next!;
     while (modifier != keyword) {
       // Recovery
       reportTopLevelModifierError(modifier, keyword);
-      modifier = modifier.next;
+      modifier = modifier.next!;
     }
   }
 
@@ -572,12 +572,12 @@
   /// Parse any top-level declaration that begins with a keyword.
   /// [start] is the token before any modifiers preceding [keyword].
   Token parseTopLevelKeywordDeclaration(
-      Token start, Token keyword, DirectiveContext directiveState) {
+      Token start, Token keyword, DirectiveContext? directiveState) {
     assert(keyword.isTopLevelKeyword);
-    final String value = keyword.stringValue;
+    final String? value = keyword.stringValue;
     if (identical(value, 'class')) {
       directiveState?.checkDeclaration();
-      Token abstractToken = parseClassDeclarationModifiers(start, keyword);
+      Token? abstractToken = parseClassDeclarationModifiers(start, keyword);
       return parseClassOrNamedMixinApplication(abstractToken, keyword);
     } else if (identical(value, 'enum')) {
       directiveState?.checkDeclaration();
@@ -588,7 +588,7 @@
       // and can be used in a top level declaration
       // as an identifier such as "abstract<T>() => 0;"
       // or as a prefix such as "abstract.A b() => 0;".
-      String nextValue = keyword.next.stringValue;
+      String? nextValue = keyword.next!.stringValue;
       if (identical(nextValue, '(') || identical(nextValue, '.')) {
         directiveState?.checkDeclaration();
         return parseTopLevelMemberImpl(start);
@@ -596,8 +596,8 @@
         if (identical(value, 'extension')) {
           // The name in an extension declaration is optional:
           // `extension<T> on ...`
-          Token endGroup = keyword.next.endGroup;
-          if (endGroup != null && optional('on', endGroup.next)) {
+          Token? endGroup = keyword.next!.endGroup;
+          if (endGroup != null && optional('on', endGroup.next!)) {
             directiveState?.checkDeclaration();
             return parseExtension(keyword);
           }
@@ -655,10 +655,10 @@
   /// ;
   /// ```
   Token parseImportPrefixOpt(Token token) {
-    Token next = token.next;
-    if (optional('deferred', next) && optional('as', next.next)) {
+    Token next = token.next!;
+    if (optional('deferred', next) && optional('as', next.next!)) {
       Token deferredToken = next;
-      Token asKeyword = next.next;
+      Token asKeyword = next.next!;
       token = ensureIdentifier(
           asKeyword, IdentifierContext.importPrefixDeclaration);
       listener.handleImportPrefix(deferredToken, asKeyword);
@@ -687,7 +687,7 @@
     Token uri = token;
     token = parseConditionalUriStar(token);
     token = parseImportPrefixOpt(token);
-    token = parseCombinatorStar(token).next;
+    token = parseCombinatorStar(token).next!;
     if (optional(';', token)) {
       listener.endImport(importKeyword, token);
       return token;
@@ -712,7 +712,7 @@
     token = parseImportPrefixOpt(token);
     token = parseCombinatorStar(token);
 
-    Token firstDeferredKeyword = recoveryListener.deferredKeyword;
+    Token? firstDeferredKeyword = recoveryListener.deferredKeyword;
     bool hasPrefix = recoveryListener.asKeyword != null;
     bool hasCombinator = recoveryListener.hasCombinator;
 
@@ -721,9 +721,9 @@
     recoveryListener.listener = primaryListener;
 
     // Parse additional out-of-order clauses.
-    Token semicolon;
+    Token? semicolon;
     do {
-      Token start = token.next;
+      Token start = token.next!;
 
       // Check for extraneous token in the middle of an import statement.
       token = skipUnexpectedTokenOpt(
@@ -746,20 +746,20 @@
         }
       }
 
-      if (optional('deferred', token.next) &&
-          !optional('as', token.next.next)) {
-        listener.handleImportPrefix(token.next, /* asKeyword = */ null);
-        token = token.next;
+      if (optional('deferred', token.next!) &&
+          !optional('as', token.next!.next!)) {
+        listener.handleImportPrefix(token.next!, /* asKeyword = */ null);
+        token = token.next!;
       } else {
         token = parseImportPrefixOpt(token);
       }
       if (recoveryListener.deferredKeyword != null) {
         if (firstDeferredKeyword != null) {
-          reportRecoverableError(
-              recoveryListener.deferredKeyword, codes.messageDuplicateDeferred);
+          reportRecoverableError(recoveryListener.deferredKeyword!,
+              codes.messageDuplicateDeferred);
         } else {
           if (hasPrefix) {
-            reportRecoverableError(recoveryListener.deferredKeyword,
+            reportRecoverableError(recoveryListener.deferredKeyword!,
                 codes.messageDeferredAfterPrefix);
           }
           firstDeferredKeyword = recoveryListener.deferredKeyword;
@@ -768,11 +768,11 @@
       if (recoveryListener.asKeyword != null) {
         if (hasPrefix) {
           reportRecoverableError(
-              recoveryListener.asKeyword, codes.messageDuplicatePrefix);
+              recoveryListener.asKeyword!, codes.messageDuplicatePrefix);
         } else {
           if (hasCombinator) {
-            reportRecoverableError(
-                recoveryListener.asKeyword, codes.messagePrefixAfterCombinator);
+            reportRecoverableError(recoveryListener.asKeyword!,
+                codes.messagePrefixAfterCombinator);
           }
           hasPrefix = true;
         }
@@ -781,9 +781,9 @@
       token = parseCombinatorStar(token);
       hasCombinator = hasCombinator || recoveryListener.hasCombinator;
 
-      if (optional(';', token.next)) {
-        semicolon = token.next;
-      } else if (identical(start, token.next)) {
+      if (optional(';', token.next!)) {
+        semicolon = token.next!;
+      } else if (identical(start, token.next!)) {
         // If no forward progress was made, insert ';' so that we exit loop.
         semicolon = ensureSemicolon(token);
       }
@@ -804,9 +804,9 @@
   /// ;
   /// ```
   Token parseConditionalUriStar(Token token) {
-    listener.beginConditionalUris(token.next);
+    listener.beginConditionalUris(token.next!);
     int count = 0;
-    while (optional('if', token.next)) {
+    while (optional('if', token.next!)) {
       count++;
       token = parseConditionalUri(token);
     }
@@ -820,25 +820,25 @@
   /// ;
   /// ```
   Token parseConditionalUri(Token token) {
-    Token ifKeyword = token = token.next;
+    Token ifKeyword = token = token.next!;
     assert(optional('if', token));
     listener.beginConditionalUri(token);
-    Token leftParen = token.next;
+    Token leftParen = token.next!;
     if (!optional('(', leftParen)) {
       reportRecoverableError(
           leftParen, codes.templateExpectedButGot.withArguments('('));
       leftParen = rewriter.insertParens(token, /* includeIdentifier = */ true);
     }
     token = parseDottedName(leftParen);
-    Token next = token.next;
-    Token equalitySign;
+    Token next = token.next!;
+    Token? equalitySign;
     if (optional('==', next)) {
       equalitySign = next;
       token = ensureLiteralString(next);
-      next = token.next;
+      next = token.next!;
     }
     if (next != leftParen.endGroup) {
-      Token endGroup = leftParen.endGroup;
+      Token endGroup = leftParen.endGroup!;
       if (endGroup.isSynthetic) {
         // The scanner did not place the synthetic ')' correctly, so move it.
         next = rewriter.moveSynthetic(token, endGroup);
@@ -864,9 +864,9 @@
     token = ensureIdentifier(token, IdentifierContext.dottedName);
     Token firstIdentifier = token;
     int count = 1;
-    while (optional('.', token.next)) {
+    while (optional('.', token.next!)) {
       token = ensureIdentifier(
-          token.next, IdentifierContext.dottedNameContinuation);
+          token.next!, IdentifierContext.dottedNameContinuation);
       count++;
     }
     listener.handleDottedName(count, firstIdentifier);
@@ -896,11 +896,11 @@
   /// ;
   /// ```
   Token parseCombinatorStar(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     listener.beginCombinators(next);
     int count = 0;
     while (true) {
-      String value = next.stringValue;
+      String? value = next.stringValue;
       if (identical('hide', value)) {
         token = parseHide(token);
       } else if (identical('show', value)) {
@@ -909,7 +909,7 @@
         listener.endCombinators(count);
         break;
       }
-      next = token.next;
+      next = token.next!;
       count++;
     }
     return token;
@@ -921,7 +921,7 @@
   /// ;
   /// ```
   Token parseHide(Token token) {
-    Token hideKeyword = token.next;
+    Token hideKeyword = token.next!;
     assert(optional('hide', hideKeyword));
     listener.beginHide(hideKeyword);
     token = parseIdentifierList(hideKeyword);
@@ -935,7 +935,7 @@
   /// ;
   /// ```
   Token parseShow(Token token) {
-    Token showKeyword = token.next;
+    Token showKeyword = token.next!;
     assert(optional('show', showKeyword));
     listener.beginShow(showKeyword);
     token = parseIdentifierList(showKeyword);
@@ -951,8 +951,8 @@
   Token parseIdentifierList(Token token) {
     token = ensureIdentifier(token, IdentifierContext.combinator);
     int count = 1;
-    while (optional(',', token.next)) {
-      token = ensureIdentifier(token.next, IdentifierContext.combinator);
+    while (optional(',', token.next!)) {
+      token = ensureIdentifier(token.next!, IdentifierContext.combinator);
       count++;
     }
     listener.handleIdentifierList(count);
@@ -965,23 +965,23 @@
   /// ;
   /// ```
   Token parseTypeList(Token token) {
-    listener.beginTypeList(token.next);
+    listener.beginTypeList(token.next!);
     token =
         computeType(token, /* required = */ true).ensureTypeOrVoid(token, this);
     int count = 1;
-    while (optional(',', token.next)) {
-      token = computeType(token.next, /* required = */ true)
-          .ensureTypeOrVoid(token.next, this);
+    while (optional(',', token.next!)) {
+      token = computeType(token.next!, /* required = */ true)
+          .ensureTypeOrVoid(token.next!, this);
       count++;
     }
     listener.endTypeList(count);
     return token;
   }
 
-  Token parsePartOrPartOf(Token partKeyword, DirectiveContext directiveState) {
+  Token parsePartOrPartOf(Token partKeyword, DirectiveContext? directiveState) {
     assert(optional('part', partKeyword));
     listener.beginUncategorizedTopLevelDeclaration(partKeyword);
-    if (optional('of', partKeyword.next)) {
+    if (optional('of', partKeyword.next!)) {
       directiveState?.checkPartOf(this, partKeyword);
       return parsePartOf(partKeyword);
     } else {
@@ -1010,11 +1010,11 @@
   /// ;
   /// ```
   Token parsePartOf(Token partKeyword) {
-    Token ofKeyword = partKeyword.next;
+    Token ofKeyword = partKeyword.next!;
     assert(optional('part', partKeyword));
     assert(optional('of', ofKeyword));
     listener.beginPartOf(partKeyword);
-    bool hasName = ofKeyword.next.isIdentifier;
+    bool hasName = ofKeyword.next!.isIdentifier;
     Token token;
     if (hasName) {
       token = parseQualified(ofKeyword, IdentifierContext.partName,
@@ -1033,9 +1033,9 @@
   /// ;
   /// ```
   Token parseMetadataStar(Token token) {
-    listener.beginMetadataStar(token.next);
+    listener.beginMetadataStar(token.next!);
     int count = 0;
-    while (optional('@', token.next)) {
+    while (optional('@', token.next!)) {
       token = parseMetadata(token);
       count++;
     }
@@ -1049,24 +1049,24 @@
   /// ;
   /// ```
   Token parseMetadata(Token token) {
-    Token atToken = token.next;
+    Token atToken = token.next!;
     assert(optional('@', atToken));
     listener.beginMetadata(atToken);
     token = ensureIdentifier(atToken, IdentifierContext.metadataReference);
     token =
         parseQualifiedRestOpt(token, IdentifierContext.metadataContinuation);
-    if (optional("<", token.next)) {
-      reportRecoverableError(token.next, codes.messageMetadataTypeArguments);
+    if (optional("<", token.next!)) {
+      reportRecoverableError(token.next!, codes.messageMetadataTypeArguments);
     }
     token = computeTypeParamOrArg(token).parseArguments(token, this);
-    Token period = null;
-    if (optional('.', token.next)) {
-      period = token.next;
+    Token? period = null;
+    if (optional('.', token.next!)) {
+      period = token.next!;
       token = ensureIdentifier(
           period, IdentifierContext.metadataContinuationAfterTypeArguments);
     }
     token = parseArgumentsOpt(token);
-    listener.endMetadata(atToken, period, token.next);
+    listener.endMetadata(atToken, period, token.next!);
     return token;
   }
 
@@ -1076,7 +1076,7 @@
   /// ;
   /// ```
   Token parseScript(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(identical(token.type, TokenType.SCRIPT_TAG));
     listener.handleScript(token);
     return token;
@@ -1109,11 +1109,11 @@
     listener.beginFunctionTypeAlias(typedefKeyword);
     TypeInfo typeInfo = computeType(typedefKeyword, /* required = */ false);
     Token token = typeInfo.skipType(typedefKeyword);
-    Token next = token.next;
-    Token equals;
+    Token next = token.next!;
+    Token? equals;
     TypeParamOrArgInfo typeParam =
         computeTypeParamOrArg(next, /* inDeclaration = */ true);
-    if (typeInfo == noType && optional('=', typeParam.skip(next).next)) {
+    if (typeInfo == noType && optional('=', typeParam.skip(next).next!)) {
       // New style typedef, e.g. typedef foo = void Function();".
 
       // Parse as recovered here to 'force' using it as an identifier as we've
@@ -1123,13 +1123,13 @@
           IdentifierContext.typedefDeclaration, /* isRecovered = */ true);
 
       token = typeParam.parseVariables(token, this);
-      next = token.next;
+      next = token.next!;
       // parseVariables rewrites so even though we checked in the if,
       // we might not have an equal here now.
-      if (!optional('=', next) && optional('=', next.next)) {
+      if (!optional('=', next) && optional('=', next.next!)) {
         // Recovery after recovery: A token was inserted, but we'll skip it now
         // to get more in line with what we thought in the if before.
-        next = next.next;
+        next = next.next!;
       }
       if (optional('=', next)) {
         equals = next;
@@ -1138,9 +1138,9 @@
           // Recovery: In certain cases insert missing 'Function' and missing
           // parens.
           Token skippedType = type.skipType(equals);
-          if (optional('(', skippedType.next) &&
-              skippedType.next.endGroup != null &&
-              optional(';', skippedType.next.endGroup.next)) {
+          if (optional('(', skippedType.next!) &&
+              skippedType.next!.endGroup != null &&
+              optional(';', skippedType.next!.endGroup!.next!)) {
             // Turn "<return type>? '(' <whatever> ')';"
             // into "<return type>? Function '(' <whatever> ')';".
             // Assume the type is meant as the return type.
@@ -1150,14 +1150,14 @@
                 codes.templateExpectedButGot.withArguments('Function'));
             type = computeType(equals, /* required = */ true);
           } else if (type is NoType &&
-              optional('<', skippedType.next) &&
-              skippedType.next.endGroup != null) {
+              optional('<', skippedType.next!) &&
+              skippedType.next!.endGroup != null) {
             // Recover these two:
             // "<whatever>;" => "Function<whatever>();"
             // "<whatever>(<whatever>);" => "Function<whatever>(<whatever>);"
-            Token endGroup = skippedType.next.endGroup;
+            Token endGroup = skippedType.next!.endGroup!;
             bool recover = false;
-            if (optional(';', endGroup.next)) {
+            if (optional(';', endGroup.next!)) {
               // Missing parenthesis. Insert them.
               // Turn "<whatever>;" in to "<whatever>();"
               // Insert missing 'Function' below.
@@ -1165,9 +1165,9 @@
                   missingParameterMessage(MemberKind.FunctionTypeAlias));
               rewriter.insertParens(endGroup, /*includeIdentifier =*/ false);
               recover = true;
-            } else if (optional('(', endGroup.next) &&
-                endGroup.next.endGroup != null &&
-                optional(';', endGroup.next.endGroup.next)) {
+            } else if (optional('(', endGroup.next!) &&
+                endGroup.next!.endGroup != null &&
+                optional(';', endGroup.next!.endGroup!.next!)) {
               // "<whatever>(<whatever>);". Insert missing 'Function' below.
               recover = true;
             }
@@ -1194,10 +1194,10 @@
     } else {
       // Old style typedef, e.g. "typedef void foo();".
       token = typeInfo.parseType(typedefKeyword, this);
-      next = token.next;
+      next = token.next!;
       bool isIdentifierRecovered = false;
       if (next.kind != IDENTIFIER_TOKEN &&
-          optional('(', typeParam.skip(next).next)) {
+          optional('(', typeParam.skip(next).next!)) {
         // Recovery: Not a valid identifier, but is used as such.
         isIdentifierRecovered = true;
       }
@@ -1215,13 +1215,13 @@
   /// Parse a mixin application starting from `with`. Assumes that the first
   /// type has already been parsed.
   Token parseMixinApplicationRest(Token token) {
-    Token withKeyword = token.next;
+    Token withKeyword = token.next!;
     if (!optional('with', withKeyword)) {
       // Recovery: Report an error and insert synthetic `with` clause.
       reportRecoverableError(
           withKeyword, codes.templateExpectedButGot.withArguments('with'));
       withKeyword = rewriter.insertSyntheticKeyword(token, Keyword.WITH);
-      if (!isValidTypeReference(withKeyword.next)) {
+      if (!isValidTypeReference(withKeyword.next!)) {
         rewriter.insertSyntheticIdentifier(withKeyword);
       }
     }
@@ -1232,7 +1232,7 @@
 
   Token parseWithClauseOpt(Token token) {
     // <mixins> ::= with <typeNotVoidList>
-    Token withKeyword = token.next;
+    Token withKeyword = token.next!;
     if (optional('with', withKeyword)) {
       token = parseTypeList(withKeyword);
       listener.handleClassWithClause(withKeyword);
@@ -1246,7 +1246,7 @@
   /// or function or method.
   Token parseGetterOrFormalParameters(
       Token token, Token name, bool isGetter, MemberKind kind) {
-    Token next = token.next;
+    Token next = token.next!;
     if (optional("(", next)) {
       if (isGetter) {
         reportRecoverableError(next, codes.messageGetterWithFormals);
@@ -1257,11 +1257,11 @@
     } else {
       // Recovery
       if (optional('operator', name)) {
-        Token next = name.next;
+        Token next = name.next!;
         if (next.isOperator) {
           name = next;
         } else if (isUnaryMinus(next)) {
-          name = next.next;
+          name = next.next!;
         }
       }
       reportRecoverableError(name, missingParameterMessage(kind));
@@ -1272,7 +1272,7 @@
   }
 
   Token parseFormalParametersOpt(Token token, MemberKind kind) {
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('(', next)) {
       token = parseFormalParameters(token, kind);
     } else {
@@ -1282,14 +1282,14 @@
   }
 
   Token skipFormalParameters(Token token, MemberKind kind) {
-    return skipFormalParametersRest(token.next, kind);
+    return skipFormalParametersRest(token.next!, kind);
   }
 
   Token skipFormalParametersRest(Token token, MemberKind kind) {
     assert(optional('(', token));
     // TODO(ahe): Shouldn't this be `beginFormalParameters`?
     listener.beginOptionalFormalParameters(token);
-    Token closeBrace = token.endGroup;
+    Token closeBrace = token.endGroup!;
     assert(optional(')', closeBrace));
     listener.endFormalParameters(/* count = */ 0, token, closeBrace, kind);
     return closeBrace;
@@ -1300,7 +1300,7 @@
   /// If `kind == MemberKind.GeneralizedFunctionType`, then names may be
   /// omitted (except for named arguments). Otherwise, types may be omitted.
   Token parseFormalParametersRequiredOpt(Token token, MemberKind kind) {
-    Token next = token.next;
+    Token next = token.next!;
     if (!optional('(', next)) {
       reportRecoverableError(next, missingParameterMessage(kind));
       next = rewriter.insertParens(token, /* includeIdentifier = */ false);
@@ -1314,7 +1314,7 @@
   /// If `kind == MemberKind.GeneralizedFunctionType`, then names may be
   /// omitted (except for named arguments). Otherwise, types may be omitted.
   Token parseFormalParameters(Token token, MemberKind kind) {
-    return parseFormalParametersRest(token.next, kind);
+    return parseFormalParametersRest(token.next!, kind);
   }
 
   /// Parses the formal parameter list of a function given that the left
@@ -1328,13 +1328,13 @@
     listener.beginFormalParameters(begin, kind);
     int parameterCount = 0;
     while (true) {
-      Token next = token.next;
+      Token next = token.next!;
       if (optional(')', next)) {
         token = next;
         break;
       }
       ++parameterCount;
-      String value = next.stringValue;
+      String? value = next.stringValue;
       if (identical(value, '[')) {
         token = parseOptionalPositionalParameters(token, kind);
         token = ensureCloseParen(token, begin);
@@ -1351,19 +1351,19 @@
         break;
       }
       token = parseFormalParameter(token, FormalParameterKind.mandatory, kind);
-      next = token.next;
+      next = token.next!;
       if (!optional(',', next)) {
-        Token next = token.next;
+        Token next = token.next!;
         if (optional(')', next)) {
           token = next;
         } else {
           // Recovery
-          if (begin.endGroup.isSynthetic) {
+          if (begin.endGroup!.isSynthetic) {
             // Scanner has already reported a missing `)` error,
             // but placed the `)` in the wrong location, so move it.
-            token = rewriter.moveSynthetic(token, begin.endGroup);
+            token = rewriter.moveSynthetic(token, begin.endGroup!);
           } else if (next.kind == IDENTIFIER_TOKEN &&
-              next.next.kind == IDENTIFIER_TOKEN) {
+              next.next!.kind == IDENTIFIER_TOKEN) {
             // Looks like a missing comma
             token = rewriteAndRecover(
                 token,
@@ -1398,17 +1398,17 @@
   /// Check if [token] is the usage of 'required' in a formal parameter in a
   /// context where it's not legal (i.e. in non-nnbd-mode).
   bool _isUseOfRequiredInNonNNBD(Token token) {
-    if (token.next is StringToken && token.next.value() == "required") {
+    if (token.next is StringToken && token.next!.value() == "required") {
       // Possible recovery: Figure out if we're in a situation like
       // required covariant? <type> name
       // (in non-nnbd-mode) where the required modifier is not legal and thus
       // would normally be parsed as the type.
-      token = token.next;
-      Token next = token.next;
+      token = token.next!;
+      Token next = token.next!;
       // Skip modifiers.
       while (next.isModifier) {
         token = next;
-        next = next.next;
+        next = next.next!;
       }
       // Parse the (potential) new type.
       TypeInfo typeInfoAlternative = computeType(
@@ -1416,7 +1416,7 @@
           /* required = */ false,
           /* inDeclaration = */ true);
       token = typeInfoAlternative.skipType(token);
-      next = token.next;
+      next = token.next!;
 
       // We've essentially ignored the 'required' at this point.
       // `token` is (in the good state) the last token of the type,
@@ -1424,7 +1424,7 @@
       // Are we in a 'good' state?
       if (typeInfoAlternative != noType &&
           next.isIdentifier &&
-          (optional(',', next.next) || optional('}', next.next))) {
+          (optional(',', next.next!) || optional('}', next.next!))) {
         return true;
       }
     }
@@ -1452,31 +1452,32 @@
   /// ```
   Token parseFormalParameter(
       Token token, FormalParameterKind parameterKind, MemberKind memberKind) {
+    // ignore: unnecessary_null_comparison
     assert(parameterKind != null);
     token = parseMetadataStar(token);
 
-    Token skippedNonRequiredRequired;
+    Token? skippedNonRequiredRequired;
     if (_isUseOfRequiredInNonNNBD(token)) {
-      skippedNonRequiredRequired = token.next;
+      skippedNonRequiredRequired = token.next!;
       reportRecoverableErrorWithToken(skippedNonRequiredRequired,
           codes.templateUnexpectedModifierInNonNnbd);
-      token = token.next;
+      token = token.next!;
     }
 
-    Token next = token.next;
+    Token next = token.next!;
     Token start = next;
 
     final bool inFunctionType =
         memberKind == MemberKind.GeneralizedFunctionType;
 
-    Token requiredToken;
-    Token covariantToken;
-    Token varFinalOrConst;
+    Token? requiredToken;
+    Token? covariantToken;
+    Token? varFinalOrConst;
     if (isModifier(next)) {
       if (optional('required', next)) {
         if (parameterKind == FormalParameterKind.optionalNamed) {
           requiredToken = token = next;
-          next = token.next;
+          next = token.next!;
         }
       }
 
@@ -1487,7 +1488,7 @@
               memberKind != MemberKind.ExtensionNonStaticMethod &&
               memberKind != MemberKind.ExtensionStaticMethod) {
             covariantToken = token = next;
-            next = token.next;
+            next = token.next!;
           }
         }
 
@@ -1495,10 +1496,10 @@
           if (!inFunctionType) {
             if (optional('var', next)) {
               varFinalOrConst = token = next;
-              next = token.next;
+              next = token.next!;
             } else if (optional('final', next)) {
               varFinalOrConst = token = next;
-              next = token.next;
+              next = token.next!;
             }
           }
 
@@ -1511,13 +1512,11 @@
 
             token = context.parseFormalParameterModifiers(
                 token, parameterKind, memberKind);
-            next = token.next;
+            next = token.next!;
 
             covariantToken = context.covariantToken;
             requiredToken = context.requiredToken;
             varFinalOrConst = context.varFinalOrConst;
-
-            context = null;
           }
         }
       }
@@ -1537,27 +1536,27 @@
     final Token beforeType = token;
     TypeInfo typeInfo = computeType(token, inFunctionType);
     token = typeInfo.skipType(token);
-    next = token.next;
+    next = token.next!;
     if (typeInfo == noType &&
         (optional('.', next) ||
-            (next.isIdentifier && optional('.', next.next)))) {
+            (next.isIdentifier && optional('.', next.next!)))) {
       // Recovery: Malformed type reference.
       typeInfo = computeType(beforeType, /* required = */ true);
       token = typeInfo.skipType(beforeType);
-      next = token.next;
+      next = token.next!;
     }
 
     final bool isNamedParameter =
         parameterKind == FormalParameterKind.optionalNamed;
 
-    Token thisKeyword;
-    Token periodAfterThis;
+    Token? thisKeyword;
+    Token? periodAfterThis;
     IdentifierContext nameContext =
         IdentifierContext.formalParameterDeclaration;
 
     if (!inFunctionType && optional('this', next)) {
       thisKeyword = token = next;
-      next = token.next;
+      next = token.next!;
       if (!optional('.', next)) {
         // Recover from a missing period by inserting one.
         next = rewriteAndRecover(
@@ -1566,28 +1565,28 @@
             new SyntheticToken(TokenType.PERIOD, next.charOffset));
       }
       periodAfterThis = token = next;
-      next = token.next;
+      next = token.next!;
       nameContext = IdentifierContext.fieldInitializer;
     }
 
     if (next.isIdentifier) {
       token = next;
-      next = token.next;
+      next = token.next!;
     }
-    Token beforeInlineFunctionType;
+    Token? beforeInlineFunctionType;
     TypeParamOrArgInfo typeParam = noTypeParamOrArg;
     if (optional("<", next)) {
       typeParam = computeTypeParamOrArg(token);
       if (typeParam != noTypeParamOrArg) {
         Token closer = typeParam.skip(token);
-        if (optional("(", closer.next)) {
+        if (optional("(", closer.next!)) {
           if (varFinalOrConst != null) {
             reportRecoverableError(
                 varFinalOrConst, codes.messageFunctionTypedParameterVar);
           }
           beforeInlineFunctionType = token;
-          token = closer.next.endGroup;
-          next = token.next;
+          token = closer.next!.endGroup!;
+          next = token.next!;
         }
       }
     } else if (optional("(", next)) {
@@ -1596,8 +1595,8 @@
             varFinalOrConst, codes.messageFunctionTypedParameterVar);
       }
       beforeInlineFunctionType = token;
-      token = next.endGroup;
-      next = token.next;
+      token = next.endGroup!;
+      next = token.next!;
     }
     if (typeInfo != noType &&
         varFinalOrConst != null &&
@@ -1605,17 +1604,18 @@
       reportRecoverableError(varFinalOrConst, codes.messageTypeAfterVar);
     }
 
-    Token endInlineFunctionType;
+    Token? endInlineFunctionType;
     if (beforeInlineFunctionType != null) {
       endInlineFunctionType =
           typeParam.parseVariables(beforeInlineFunctionType, this);
-      listener.beginFunctionTypedFormalParameter(beforeInlineFunctionType.next);
+      listener
+          .beginFunctionTypedFormalParameter(beforeInlineFunctionType.next!);
       token = typeInfo.parseType(beforeType, this);
       endInlineFunctionType = parseFormalParametersRequiredOpt(
           endInlineFunctionType, MemberKind.FunctionTypedParameter);
-      Token question;
-      if (optional('?', endInlineFunctionType.next)) {
-        question = endInlineFunctionType = endInlineFunctionType.next;
+      Token? question;
+      if (optional('?', endInlineFunctionType.next!)) {
+        question = endInlineFunctionType = endInlineFunctionType.next!;
       }
       listener.endFunctionTypedFormalParameter(
           beforeInlineFunctionType, question);
@@ -1624,7 +1624,7 @@
       // The following isn't allowed:
       //    int Function(int bar(String x)).
       if (inFunctionType) {
-        reportRecoverableError(beforeInlineFunctionType.next,
+        reportRecoverableError(beforeInlineFunctionType.next!,
             codes.messageInvalidInlineFunctionType);
       }
     } else if (inFunctionType) {
@@ -1637,12 +1637,12 @@
     if (periodAfterThis != null) {
       token = periodAfterThis;
     }
-    next = token.next;
+    next = token.next!;
     if (inFunctionType &&
         !isNamedParameter &&
         !next.isKeywordOrIdentifier &&
         beforeInlineFunctionType == null) {
-      nameToken = token.next;
+      nameToken = token.next!;
       listener.handleNoName(nameToken);
     } else {
       nameToken = token = ensureIdentifier(token, nameContext);
@@ -1653,16 +1653,16 @@
     if (endInlineFunctionType != null) {
       token = endInlineFunctionType;
     }
-    next = token.next;
+    next = token.next!;
 
-    String value = next.stringValue;
-    Token initializerStart, initializerEnd;
+    String? value = next.stringValue;
+    Token? initializerStart, initializerEnd;
     if ((identical('=', value)) || (identical(':', value))) {
       Token equal = next;
-      initializerStart = equal.next;
+      initializerStart = equal.next!;
       listener.beginFormalParameterDefaultValueExpression();
       token = initializerEnd = parseExpression(equal);
-      next = token.next;
+      next = token.next!;
       listener.endFormalParameterDefaultValueExpression();
       // TODO(danrubel): Consider removing the last parameter from the
       // handleValuedFormalParameter event... it appears to be unused.
@@ -1693,18 +1693,18 @@
   /// ;
   /// ```
   Token parseOptionalPositionalParameters(Token token, MemberKind kind) {
-    Token begin = token = token.next;
+    Token begin = token = token.next!;
     assert(optional('[', token));
     listener.beginOptionalFormalParameters(begin);
     int parameterCount = 0;
     while (true) {
-      Token next = token.next;
+      Token next = token.next!;
       if (optional(']', next)) {
         break;
       }
       token = parseFormalParameter(
           token, FormalParameterKind.optionalPositional, kind);
-      next = token.next;
+      next = token.next!;
       ++parameterCount;
       if (!optional(',', next)) {
         if (!optional(']', next)) {
@@ -1712,9 +1712,9 @@
           reportRecoverableError(
               next, codes.templateExpectedButGot.withArguments(']'));
           // Scanner guarantees a closing bracket.
-          next = begin.endGroup;
+          next = begin.endGroup!;
           while (token.next != next) {
-            token = token.next;
+            token = token.next!;
           }
         }
         break;
@@ -1726,12 +1726,12 @@
           token,
           codes.messageEmptyOptionalParameterList,
           new SyntheticStringToken(TokenType.IDENTIFIER, '',
-              token.next.charOffset, /* _length = */ 0));
+              token.next!.charOffset, /* _length = */ 0));
       token = parseFormalParameter(
           token, FormalParameterKind.optionalPositional, kind);
       ++parameterCount;
     }
-    token = token.next;
+    token = token.next!;
     assert(optional(']', token));
     listener.endOptionalFormalParameters(parameterCount, begin, token);
     return token;
@@ -1744,18 +1744,18 @@
   /// ;
   /// ```
   Token parseOptionalNamedParameters(Token token, MemberKind kind) {
-    Token begin = token = token.next;
+    Token begin = token = token.next!;
     assert(optional('{', token));
     listener.beginOptionalFormalParameters(begin);
     int parameterCount = 0;
     while (true) {
-      Token next = token.next;
+      Token next = token.next!;
       if (optional('}', next)) {
         break;
       }
       token =
           parseFormalParameter(token, FormalParameterKind.optionalNamed, kind);
-      next = token.next;
+      next = token.next!;
       ++parameterCount;
       if (!optional(',', next)) {
         if (!optional('}', next)) {
@@ -1763,9 +1763,9 @@
           reportRecoverableError(
               next, codes.templateExpectedButGot.withArguments('}'));
           // Scanner guarantees a closing bracket.
-          next = begin.endGroup;
+          next = begin.endGroup!;
           while (token.next != next) {
-            token = token.next;
+            token = token.next!;
           }
         }
         break;
@@ -1777,12 +1777,12 @@
           token,
           codes.messageEmptyNamedParameterList,
           new SyntheticStringToken(TokenType.IDENTIFIER, '',
-              token.next.charOffset, /* _length = */ 0));
+              token.next!.charOffset, /* _length = */ 0));
       token =
           parseFormalParameter(token, FormalParameterKind.optionalNamed, kind);
       ++parameterCount;
     }
-    token = token.next;
+    token = token.next!;
     assert(optional('}', token));
     listener.endOptionalFormalParameters(parameterCount, begin, token);
     return token;
@@ -1796,7 +1796,7 @@
   Token parseQualified(Token token, IdentifierContext context,
       IdentifierContext continuationContext) {
     token = ensureIdentifier(token, context);
-    while (optional('.', token.next)) {
+    while (optional('.', token.next!)) {
       token = parseQualifiedRest(token, continuationContext);
     }
     return token;
@@ -1809,7 +1809,7 @@
   /// ```
   Token parseQualifiedRestOpt(
       Token token, IdentifierContext continuationContext) {
-    if (optional('.', token.next)) {
+    if (optional('.', token.next!)) {
       return parseQualifiedRest(token, continuationContext);
     } else {
       return token;
@@ -1822,7 +1822,7 @@
   /// ;
   /// ```
   Token parseQualifiedRest(Token token, IdentifierContext context) {
-    token = token.next;
+    token = token.next!;
     assert(optional('.', token));
     Token period = token;
     token = ensureIdentifier(token, context);
@@ -1834,7 +1834,7 @@
     // The scanner ensures that `{` always has a closing `}`.
     return ensureBlock(
             token, /* template = */ null, /* missingBlockName = */ null)
-        .endGroup;
+        .endGroup!;
   }
 
   /// ```
@@ -1848,12 +1848,12 @@
     listener.beginEnum(enumKeyword);
     Token token =
         ensureIdentifier(enumKeyword, IdentifierContext.enumDeclaration);
-    Token leftBrace = token.next;
+    Token leftBrace = token.next!;
     int count = 0;
     if (optional('{', leftBrace)) {
       token = leftBrace;
       while (true) {
-        Token next = token.next;
+        Token next = token.next!;
         if (optional('}', next)) {
           token = next;
           if (count == 0) {
@@ -1863,7 +1863,7 @@
         }
         token = parseMetadataStar(token);
         token = ensureIdentifier(token, IdentifierContext.enumValueDeclaration);
-        next = token.next;
+        next = token.next!;
         count++;
         if (optional(',', next)) {
           token = next;
@@ -1872,7 +1872,7 @@
           break;
         } else {
           // Recovery
-          Token endGroup = leftBrace.endGroup;
+          Token endGroup = leftBrace.endGroup!;
           if (endGroup.isSynthetic) {
             // The scanner did not place the synthetic '}' correctly.
             token = rewriter.moveSynthetic(token, endGroup);
@@ -1888,7 +1888,7 @@
             // Otherwise assume a missing `}` and exit the loop
             reportRecoverableError(
                 next, codes.templateExpectedButGot.withArguments('}'));
-            token = leftBrace.endGroup;
+            token = leftBrace.endGroup!;
             break;
           }
         }
@@ -1897,7 +1897,7 @@
       // TODO(danrubel): merge this error message with missing class/mixin body
       leftBrace = ensureBlock(
           token, codes.templateExpectedEnumBody, /* missingBlockName = */ null);
-      token = leftBrace.endGroup;
+      token = leftBrace.endGroup!;
     }
     assert(optional('}', token));
     listener.endEnum(enumKeyword, leftBrace, count);
@@ -1905,7 +1905,7 @@
   }
 
   Token parseClassOrNamedMixinApplication(
-      Token abstractToken, Token classKeyword) {
+      Token? abstractToken, Token classKeyword) {
     assert(optional('class', classKeyword));
     Token begin = abstractToken ?? classKeyword;
     listener.beginClassOrNamedMixinApplicationPrelude(begin);
@@ -1914,7 +1914,7 @@
     Token token = computeTypeParamOrArg(
             name, /* inDeclaration = */ true, /* allowsVariance = */ true)
         .parseVariables(name, this);
-    if (optional('=', token.next)) {
+    if (optional('=', token.next!)) {
       listener.beginNamedMixinApplication(begin, abstractToken, name);
       return parseNamedMixinApplication(token, begin, classKeyword);
     } else {
@@ -1925,14 +1925,14 @@
 
   Token parseNamedMixinApplication(
       Token token, Token begin, Token classKeyword) {
-    Token equals = token = token.next;
+    Token equals = token = token.next!;
     assert(optional('=', equals));
     token = computeType(token, /* required = */ true)
         .ensureTypeNotVoid(token, this);
     token = parseMixinApplicationRest(token);
-    Token implementsKeyword = null;
-    if (optional('implements', token.next)) {
-      implementsKeyword = token.next;
+    Token? implementsKeyword = null;
+    if (optional('implements', token.next!)) {
+      implementsKeyword = token.next!;
       token = parseTypeList(implementsKeyword);
     }
     token = ensureSemicolon(token);
@@ -1956,7 +1956,7 @@
       Token token, Token begin, Token classKeyword, String className) {
     Token start = token;
     token = parseClassHeaderOpt(token, begin, classKeyword);
-    if (!optional('{', token.next)) {
+    if (!optional('{', token.next!)) {
       // Recovery
       token = parseClassHeaderRecovery(start, begin, classKeyword);
       ensureBlock(token, /* template = */ null, 'class declaration');
@@ -1971,9 +1971,9 @@
     token = parseClassExtendsOpt(token);
     token = parseWithClauseOpt(token);
     token = parseClassOrMixinImplementsOpt(token);
-    Token nativeToken;
-    if (optional('native', token.next)) {
-      nativeToken = token.next;
+    Token? nativeToken;
+    if (optional('native', token.next!)) {
+      nativeToken = token.next!;
       token = parseNativeClause(token);
     }
     listener.handleClassHeader(begin, classKeyword, nativeToken);
@@ -2011,11 +2011,11 @@
       // and generate the same events as in the parseClassHeader method above.
       recoveryListener.clear();
 
-      if (token.next.isKeywordOrIdentifier &&
-          const ['extend', 'on'].contains(token.next.lexeme)) {
-        reportRecoverableError(
-            token.next, codes.templateExpectedInstead.withArguments('extends'));
-        token = parseClassExtendsSeenExtendsClause(token.next, token);
+      if (token.next!.isKeywordOrIdentifier &&
+          const ['extend', 'on'].contains(token.next!.lexeme)) {
+        reportRecoverableError(token.next!,
+            codes.templateExpectedInstead.withArguments('extends'));
+        token = parseClassExtendsSeenExtendsClause(token.next!, token);
       } else {
         token = parseClassExtendsOpt(token);
       }
@@ -2023,13 +2023,13 @@
       if (recoveryListener.extendsKeyword != null) {
         if (hasExtends) {
           reportRecoverableError(
-              recoveryListener.extendsKeyword, codes.messageMultipleExtends);
+              recoveryListener.extendsKeyword!, codes.messageMultipleExtends);
         } else {
           if (hasWith) {
-            reportRecoverableError(recoveryListener.extendsKeyword,
+            reportRecoverableError(recoveryListener.extendsKeyword!,
                 codes.messageWithBeforeExtends);
           } else if (hasImplements) {
-            reportRecoverableError(recoveryListener.extendsKeyword,
+            reportRecoverableError(recoveryListener.extendsKeyword!,
                 codes.messageImplementsBeforeExtends);
           }
           hasExtends = true;
@@ -2041,10 +2041,10 @@
       if (recoveryListener.withKeyword != null) {
         if (hasWith) {
           reportRecoverableError(
-              recoveryListener.withKeyword, codes.messageMultipleWith);
+              recoveryListener.withKeyword!, codes.messageMultipleWith);
         } else {
           if (hasImplements) {
-            reportRecoverableError(recoveryListener.withKeyword,
+            reportRecoverableError(recoveryListener.withKeyword!,
                 codes.messageImplementsBeforeWith);
           }
           hasWith = true;
@@ -2055,7 +2055,7 @@
 
       if (recoveryListener.implementsKeyword != null) {
         if (hasImplements) {
-          reportRecoverableError(recoveryListener.implementsKeyword,
+          reportRecoverableError(recoveryListener.implementsKeyword!,
               codes.messageMultipleImplements);
         } else {
           hasImplements = true;
@@ -2065,7 +2065,7 @@
       listener.handleRecoverClassHeader();
 
       // Exit if a class body is detected, or if no progress has been made
-    } while (!optional('{', token.next) && start != token);
+    } while (!optional('{', token.next!) && start != token);
 
     listener = primaryListener;
     return token;
@@ -2073,7 +2073,7 @@
 
   Token parseClassExtendsOpt(Token token) {
     // extends <typeNotVoid>
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('extends', next)) {
       token = parseClassExtendsSeenExtendsClause(next, token);
     } else {
@@ -2092,11 +2092,11 @@
     int count = 1;
 
     // Error recovery: extends <typeNotVoid>, <typeNotVoid> [...]
-    if (optional(',', token.next)) {
-      reportRecoverableError(token.next, codes.messageMultipleExtends);
+    if (optional(',', token.next!)) {
+      reportRecoverableError(token.next!, codes.messageMultipleExtends);
 
-      while (optional(',', token.next)) {
-        next = token.next;
+      while (optional(',', token.next!)) {
+        next = token.next!;
         token = computeType(next, /* required = */ true)
             .ensureTypeNotVoid(next, this);
         count++;
@@ -2113,15 +2113,15 @@
   /// ;
   /// ```
   Token parseClassOrMixinImplementsOpt(Token token) {
-    Token implementsKeyword;
+    Token? implementsKeyword;
     int interfacesCount = 0;
-    if (optional('implements', token.next)) {
-      implementsKeyword = token.next;
+    if (optional('implements', token.next!)) {
+      implementsKeyword = token.next!;
       do {
-        token = computeType(token.next, /* required = */ true)
-            .ensureTypeNotVoid(token.next, this);
+        token = computeType(token.next!, /* required = */ true)
+            .ensureTypeNotVoid(token.next!, this);
         ++interfacesCount;
-      } while (optional(',', token.next));
+      } while (optional(',', token.next!));
     }
     listener.handleClassOrMixinImplements(implementsKeyword, interfacesCount);
     return token;
@@ -2145,7 +2145,7 @@
         .parseVariables(name, this);
     listener.beginMixinDeclaration(mixinKeyword, name);
     Token token = parseMixinHeaderOpt(headerStart, mixinKeyword);
-    if (!optional('{', token.next)) {
+    if (!optional('{', token.next!)) {
       // Recovery
       token = parseMixinHeaderRecovery(token, mixinKeyword, headerStart);
       ensureBlock(token, /* template = */ null, 'mixin declaration');
@@ -2193,10 +2193,10 @@
       // generate the same events as in the parseMixinHeaderOpt method above.
       recoveryListener.clear();
 
-      if (token.next.isKeywordOrIdentifier &&
-          const ['extend', 'extends'].contains(token.next.lexeme)) {
+      if (token.next!.isKeywordOrIdentifier &&
+          const ['extend', 'extends'].contains(token.next!.lexeme)) {
         reportRecoverableError(
-            token.next, codes.templateExpectedInstead.withArguments('on'));
+            token.next!, codes.templateExpectedInstead.withArguments('on'));
         token = parseMixinOn(token);
       } else {
         token = parseMixinOnOpt(token);
@@ -2205,11 +2205,11 @@
       if (recoveryListener.onKeyword != null) {
         if (hasOn) {
           reportRecoverableError(
-              recoveryListener.onKeyword, codes.messageMultipleOnClauses);
+              recoveryListener.onKeyword!, codes.messageMultipleOnClauses);
         } else {
           if (hasImplements) {
             reportRecoverableError(
-                recoveryListener.onKeyword, codes.messageImplementsBeforeOn);
+                recoveryListener.onKeyword!, codes.messageImplementsBeforeOn);
           }
           hasOn = true;
         }
@@ -2219,7 +2219,7 @@
 
       if (recoveryListener.implementsKeyword != null) {
         if (hasImplements) {
-          reportRecoverableError(recoveryListener.implementsKeyword,
+          reportRecoverableError(recoveryListener.implementsKeyword!,
               codes.messageMultipleImplements);
         } else {
           hasImplements = true;
@@ -2229,7 +2229,7 @@
       listener.handleRecoverMixinHeader();
 
       // Exit if a mixin body is detected, or if no progress has been made
-    } while (!optional('{', token.next) && start != token);
+    } while (!optional('{', token.next!) && start != token);
 
     listener = primaryListener;
     return token;
@@ -2241,7 +2241,7 @@
   /// ;
   /// ```
   Token parseMixinOnOpt(Token token) {
-    if (!optional('on', token.next)) {
+    if (!optional('on', token.next!)) {
       listener.handleMixinOn(/* onKeyword = */ null, /* typeCount = */ 0);
       return token;
     }
@@ -2249,17 +2249,17 @@
   }
 
   Token parseMixinOn(Token token) {
-    Token onKeyword = token.next;
+    Token onKeyword = token.next!;
     // During recovery, the [onKeyword] can be "extend" or "extends"
     assert(optional('on', onKeyword) ||
         optional('extends', onKeyword) ||
         onKeyword.lexeme == 'extend');
     int typeCount = 0;
     do {
-      token = computeType(token.next, /* required = */ true)
-          .ensureTypeNotVoid(token.next, this);
+      token = computeType(token.next!, /* required = */ true)
+          .ensureTypeNotVoid(token.next!, this);
       ++typeCount;
-    } while (optional(',', token.next));
+    } while (optional(',', token.next!));
     listener.handleMixinOn(onKeyword, typeCount);
     return token;
   }
@@ -2274,7 +2274,7 @@
     assert(optional('extension', extensionKeyword));
     Token token = extensionKeyword;
     listener.beginExtensionDeclarationPrelude(extensionKeyword);
-    Token name = token.next;
+    Token? name = token.next!;
     if (name.isIdentifier && !optional('on', name)) {
       token = name;
       if (name.type.isBuiltIn) {
@@ -2287,7 +2287,7 @@
     token = computeTypeParamOrArg(token, /* inDeclaration = */ true)
         .parseVariables(token, this);
     listener.beginExtensionDeclaration(extensionKeyword, name);
-    Token onKeyword = token.next;
+    Token onKeyword = token.next!;
     if (!optional('on', onKeyword)) {
       // Recovery
       if (optional('extends', onKeyword) ||
@@ -2303,9 +2303,9 @@
     }
     TypeInfo typeInfo = computeType(onKeyword, /* required = */ true);
     token = typeInfo.ensureTypeOrVoid(onKeyword, this);
-    if (!optional('{', token.next)) {
+    if (!optional('{', token.next!)) {
       // Recovery
-      Token next = token.next;
+      Token next = token.next!;
       while (!next.isEof) {
         if (optional(',', next) ||
             optional('extends', next) ||
@@ -2316,10 +2316,10 @@
           // optionally followed by an identifier
           reportRecoverableErrorWithToken(next, codes.templateUnexpectedToken);
           token = next;
-          next = token.next;
+          next = token.next!;
           if (next.isIdentifier) {
             token = next;
-            next = token.next;
+            next = token.next!;
           }
         } else {
           break;
@@ -2334,7 +2334,7 @@
   }
 
   Token parseStringPart(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     if (next.kind != STRING_TOKEN) {
       reportRecoverableErrorWithToken(next, codes.templateExpectedString);
       next = rewriter.insertToken(token,
@@ -2348,8 +2348,8 @@
   /// message based on the given [context]. Return the synthetic identifier that
   /// was inserted.
   Token insertSyntheticIdentifier(Token token, IdentifierContext context,
-      {codes.Message message, Token messageOnToken}) {
-    Token next = token.next;
+      {codes.Message? message, Token? messageOnToken}) {
+    Token next = token.next!;
     reportRecoverableError(messageOnToken ?? next,
         message ?? context.recoveryTemplate.withArguments(next));
     return rewriter.insertSyntheticIdentifier(token);
@@ -2362,10 +2362,12 @@
   /// identifier in the given [context], create a synthetic identifier, report
   /// an error, and return the synthetic identifier.
   Token ensureIdentifier(Token token, IdentifierContext context) {
+    // ignore: unnecessary_null_comparison
     assert(context != null);
-    Token identifier = token.next;
+    Token identifier = token.next!;
     if (identifier.kind != IDENTIFIER_TOKEN) {
       identifier = context.ensureIdentifier(token, this);
+      // ignore: unnecessary_null_comparison
       assert(identifier != null);
       assert(identifier.isKeywordOrIdentifier);
     }
@@ -2383,11 +2385,13 @@
   /// to use the token as an identifier, even if it isn't a valid identifier.
   Token ensureIdentifierPotentiallyRecovered(
       Token token, IdentifierContext context, bool isRecovered) {
+    // ignore: unnecessary_null_comparison
     assert(context != null);
-    Token identifier = token.next;
+    Token identifier = token.next!;
     if (identifier.kind != IDENTIFIER_TOKEN) {
       identifier = context.ensureIdentifierPotentiallyRecovered(
           token, this, isRecovered);
+      // ignore: unnecessary_null_comparison
       assert(identifier != null);
       assert(identifier.isKeywordOrIdentifier);
     }
@@ -2413,7 +2417,7 @@
   /// last consumed token.
   Token parseTopLevelMember(Token token) {
     token = parseMetadataStar(syntheticPreviousToken(token));
-    return parseTopLevelMemberImpl(token).next;
+    return parseTopLevelMemberImpl(token).next!;
   }
 
   /// Check if [token] is the usage of 'late' before a field declaration in a
@@ -2424,11 +2428,11 @@
       // late final? <type>/var/const name [...]
       // (in non-nnbd-mode) where the late modifier is not legal and thus would
       // normally be parsed as the type.
-      Token next = token.next;
+      Token next = token.next!;
       // Skip modifiers.
       while (next.isModifier) {
         token = next;
-        next = next.next;
+        next = next.next!;
       }
       // Parse the (potential) new type.
       TypeInfo typeInfoAlternative = computeType(
@@ -2436,7 +2440,7 @@
           /* required = */ false,
           /* inDeclaration = */ true);
       token = typeInfoAlternative.skipType(token);
-      next = token.next;
+      next = token.next!;
 
       // We've essentially ignored the 'late' at this point.
       // `token` is (in the good state) the last token of the type,
@@ -2444,7 +2448,7 @@
       // Are we in a 'good' state?
       if (typeInfoAlternative != noType &&
           next.isIdentifier &&
-          indicatesMethodOrField(next.next)) {
+          indicatesMethodOrField(next.next!)) {
         return true;
       }
     }
@@ -2453,45 +2457,45 @@
 
   Token parseTopLevelMemberImpl(Token token) {
     Token beforeStart = token;
-    Token next = token.next;
+    Token next = token.next!;
     listener.beginTopLevelMember(next);
 
-    Token skippedNonLateLate;
+    Token? skippedNonLateLate;
 
     if (_isUseOfLateInNonNNBD(next)) {
       skippedNonLateLate = next;
       reportRecoverableErrorWithToken(
           skippedNonLateLate, codes.templateUnexpectedModifierInNonNnbd);
-      token = token.next;
+      token = token.next!;
       beforeStart = token;
-      next = token.next;
+      next = token.next!;
     }
 
-    Token externalToken;
-    Token lateToken;
-    Token varFinalOrConst;
+    Token? externalToken;
+    Token? lateToken;
+    Token? varFinalOrConst;
 
     if (isModifier(next)) {
       if (optional('external', next)) {
         externalToken = token = next;
-        next = token.next;
+        next = token.next!;
       }
       if (isModifier(next)) {
         if (optional('final', next)) {
           varFinalOrConst = token = next;
-          next = token.next;
+          next = token.next!;
         } else if (optional('var', next)) {
           varFinalOrConst = token = next;
-          next = token.next;
+          next = token.next!;
         } else if (optional('const', next)) {
           varFinalOrConst = token = next;
-          next = token.next;
+          next = token.next!;
         } else if (optional('late', next)) {
           lateToken = token = next;
-          next = token.next;
+          next = token.next!;
           if (isModifier(next) && optional('final', next)) {
             varFinalOrConst = token = next;
-            next = token.next;
+            next = token.next!;
           }
         }
         if (isModifier(next)) {
@@ -2509,13 +2513,11 @@
               ..varFinalOrConst = varFinalOrConst;
 
             token = context.parseTopLevelModifiers(token);
-            next = token.next;
+            next = token.next!;
 
             externalToken = context.externalToken;
             lateToken = context.lateToken;
             varFinalOrConst = context.varFinalOrConst;
-
-            context = null;
           }
         }
       }
@@ -2531,14 +2533,14 @@
     TypeInfo typeInfo =
         computeType(token, /* required = */ false, /* inDeclaration = */ true);
     token = typeInfo.skipType(token);
-    next = token.next;
+    next = token.next!;
 
-    Token getOrSet;
-    String value = next.stringValue;
+    Token? getOrSet;
+    String? value = next.stringValue;
     if (identical(value, 'get') || identical(value, 'set')) {
-      if (next.next.isIdentifier) {
+      if (next.next!.isIdentifier) {
         getOrSet = token = next;
-        next = token.next;
+        next = token.next!;
       }
     }
 
@@ -2549,15 +2551,15 @@
     // take the reserved keyword as the name.
     if (typeInfo == noType &&
         varFinalOrConst == null &&
-        isReservedKeyword(next.next) &&
-        indicatesMethodOrField(next.next.next)) {
+        isReservedKeyword(next.next!) &&
+        indicatesMethodOrField(next.next!.next!)) {
       // Recovery: Use the reserved keyword despite that not being legal.
       typeInfo = computeType(
           token,
           /*required = */ true,
           /* inDeclaration = */ true);
       token = typeInfo.skipType(token);
-      next = token.next;
+      next = token.next!;
       nameIsRecovered = true;
     }
 
@@ -2565,7 +2567,7 @@
       value = next.stringValue;
       if (identical(value, 'factory') || identical(value, 'operator')) {
         // `factory` and `operator` can be used as an identifier.
-        value = next.next.stringValue;
+        value = next.next!.stringValue;
         if (getOrSet == null &&
             !identical(value, '(') &&
             !identical(value, '{') &&
@@ -2581,10 +2583,10 @@
                 next, codes.messageFactoryTopLevelDeclaration);
           } else {
             reportRecoverableError(next, codes.messageTopLevelOperator);
-            if (next.next.isOperator) {
+            if (next.next!.isOperator) {
               token = next;
-              next = token.next;
-              if (optional('(', next.next)) {
+              next = token.next!;
+              if (optional('(', next.next!)) {
                 rewriter.insertSyntheticIdentifier(
                     next, '#synthetic_identifier_${next.charOffset}');
               }
@@ -2606,18 +2608,18 @@
           // Looks like a declaration missing an identifier.
           // Insert synthetic identifier and fall through.
           insertSyntheticIdentifier(token, IdentifierContext.methodDeclaration);
-          next = token.next;
+          next = token.next!;
         }
       }
     }
     // At this point, `token` is beforeName.
 
     // Recovery: Inserted ! after method name.
-    if (optional('!', next.next)) {
-      next = next.next;
+    if (optional('!', next.next!)) {
+      next = next.next!;
     }
 
-    next = next.next;
+    next = next.next!;
     value = next.stringValue;
     if (getOrSet != null ||
         identical(value, '(') ||
@@ -2637,7 +2639,7 @@
             lateToken, codes.templateExtraneousModifier);
       }
       return parseTopLevelMethod(beforeStart, externalToken, beforeType,
-          typeInfo, getOrSet, token.next, nameIsRecovered);
+          typeInfo, getOrSet, token.next!, nameIsRecovered);
     }
 
     if (getOrSet != null) {
@@ -2654,7 +2656,7 @@
         varFinalOrConst,
         beforeType,
         typeInfo,
-        token.next,
+        token.next!,
         DeclarationKind.TopLevel,
         /* enclosingDeclarationName = */ null,
         nameIsRecovered);
@@ -2662,17 +2664,17 @@
 
   Token parseFields(
       Token beforeStart,
-      Token abstractToken,
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       Token beforeType,
       TypeInfo typeInfo,
       Token name,
       DeclarationKind kind,
-      String enclosingDeclarationName,
+      String? enclosingDeclarationName,
       bool nameIsRecovered) {
     listener.beginFields(beforeStart);
 
@@ -2700,7 +2702,7 @@
     }
 
     Token token = typeInfo.parseType(beforeType, this);
-    assert(token.next == name || token.next.isEof);
+    assert(token.next == name || token.next!.isEof);
 
     IdentifierContext context = kind == DeclarationKind.TopLevel
         ? IdentifierContext.topLevelVariableDeclaration
@@ -2711,7 +2713,7 @@
     // Check for covariant late final with initializer.
     if (covariantToken != null && lateToken != null) {
       if (varFinalOrConst != null && optional('final', varFinalOrConst)) {
-        Token next = name.next;
+        Token next = name.next!;
         if (optional('=', next)) {
           reportRecoverableError(covariantToken,
               codes.messageFinalAndCovariantLateWithInitializer);
@@ -2723,26 +2725,26 @@
     int fieldCount = 1;
     token = parseFieldInitializerOpt(name, name, lateToken, abstractToken,
         externalToken, varFinalOrConst, kind, enclosingDeclarationName);
-    while (optional(',', token.next)) {
-      name = ensureIdentifier(token.next, context);
+    while (optional(',', token.next!)) {
+      name = ensureIdentifier(token.next!, context);
       token = parseFieldInitializerOpt(name, name, lateToken, abstractToken,
           externalToken, varFinalOrConst, kind, enclosingDeclarationName);
       ++fieldCount;
     }
-    Token semicolon = token.next;
+    Token semicolon = token.next!;
     if (optional(';', semicolon)) {
       token = semicolon;
     } else {
       // Recovery
       if (kind == DeclarationKind.TopLevel &&
-          beforeType.next.isIdentifier &&
-          beforeType.next.lexeme == 'extension') {
+          beforeType.next!.isIdentifier &&
+          beforeType.next!.lexeme == 'extension') {
         // Looks like an extension method
         // TODO(danrubel): Remove when extension methods are enabled by default
         // because then 'extension' will be interpreted as a built-in
         // and this code will never be executed
         reportRecoverableError(
-            beforeType.next,
+            beforeType.next!,
             codes.templateExperimentNotEnabled
                 .withArguments('extension-methods', '2.6'));
         token = rewriter.insertSyntheticToken(token, TokenType.SEMICOLON);
@@ -2754,7 +2756,7 @@
       case DeclarationKind.TopLevel:
         assert(abstractToken == null);
         listener.endTopLevelFields(externalToken, staticToken, covariantToken,
-            lateToken, varFinalOrConst, fieldCount, beforeStart.next, token);
+            lateToken, varFinalOrConst, fieldCount, beforeStart.next!, token);
         break;
       case DeclarationKind.Class:
         listener.endClassFields(
@@ -2765,7 +2767,7 @@
             lateToken,
             varFinalOrConst,
             fieldCount,
-            beforeStart.next,
+            beforeStart.next!,
             token);
         break;
       case DeclarationKind.Mixin:
@@ -2777,7 +2779,7 @@
             lateToken,
             varFinalOrConst,
             fieldCount,
-            beforeStart.next,
+            beforeStart.next!,
             token);
         break;
       case DeclarationKind.Extension:
@@ -2797,7 +2799,7 @@
             lateToken,
             varFinalOrConst,
             fieldCount,
-            beforeStart.next,
+            beforeStart.next!,
             token);
         break;
     }
@@ -2806,16 +2808,16 @@
 
   Token parseTopLevelMethod(
       Token beforeStart,
-      Token externalToken,
+      Token? externalToken,
       Token beforeType,
       TypeInfo typeInfo,
-      Token getOrSet,
+      Token? getOrSet,
       Token name,
       bool nameIsRecovered) {
     listener.beginTopLevelMethod(beforeStart, externalToken);
 
     Token token = typeInfo.parseType(beforeType, this);
-    assert(token.next == (getOrSet ?? name) || token.next.isEof);
+    assert(token.next == (getOrSet ?? name) || token.next!.isEof);
     name = ensureIdentifierPotentiallyRecovered(
         getOrSet ?? token,
         IdentifierContext.topLevelFunctionDeclaration,
@@ -2827,43 +2829,43 @@
     } else {
       isGetter = optional("get", getOrSet);
       token = name;
-      listener.handleNoTypeVariables(token.next);
+      listener.handleNoTypeVariables(token.next!);
     }
     token = parseGetterOrFormalParameters(
         token, name, isGetter, MemberKind.TopLevelMethod);
     AsyncModifier savedAsyncModifier = asyncState;
-    Token asyncToken = token.next;
+    Token asyncToken = token.next!;
     token = parseAsyncModifierOpt(token);
     if (getOrSet != null && !inPlainSync && optional("set", getOrSet)) {
       reportRecoverableError(asyncToken, codes.messageSetterNotSync);
     }
     bool isExternal = externalToken != null;
-    if (isExternal && !optional(';', token.next)) {
+    if (isExternal && !optional(';', token.next!)) {
       reportRecoverableError(
-          externalToken, codes.messageExternalMethodWithBody);
+          externalToken!, codes.messageExternalMethodWithBody);
     }
     token = parseFunctionBody(
         token, /* ofFunctionExpression = */ false, isExternal);
     asyncState = savedAsyncModifier;
-    listener.endTopLevelMethod(beforeStart.next, getOrSet, token);
+    listener.endTopLevelMethod(beforeStart.next!, getOrSet, token);
     return token;
   }
 
   Token parseMethodTypeVar(Token name) {
-    if (optional('!', name.next)) {
+    if (optional('!', name.next!)) {
       // Recovery
-      name = name.next;
+      name = name.next!;
       reportRecoverableErrorWithToken(name, codes.templateUnexpectedToken);
     }
-    if (!optional('<', name.next)) {
+    if (!optional('<', name.next!)) {
       return noTypeParamOrArg.parseVariables(name, this);
     }
     TypeParamOrArgInfo typeVar =
         computeTypeParamOrArg(name, /* inDeclaration = */ true);
     Token token = typeVar.parseVariables(name, this);
-    if (optional('=', token.next)) {
+    if (optional('=', token.next!)) {
       // Recovery
-      token = token.next;
+      token = token.next!;
       reportRecoverableErrorWithToken(token, codes.templateUnexpectedToken);
     }
     return token;
@@ -2872,21 +2874,21 @@
   Token parseFieldInitializerOpt(
       Token token,
       Token name,
-      Token lateToken,
-      Token abstractToken,
-      Token externalToken,
-      Token varFinalOrConst,
+      Token? lateToken,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? varFinalOrConst,
       DeclarationKind kind,
-      String enclosingDeclarationName) {
+      String? enclosingDeclarationName) {
     if (name.lexeme == enclosingDeclarationName) {
       reportRecoverableError(name, codes.messageMemberWithSameNameAsClass);
     }
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('=', next)) {
       Token assignment = next;
       listener.beginFieldInitializer(next);
       token = parseExpression(next);
-      listener.endFieldInitializer(assignment, token.next);
+      listener.endFieldInitializer(assignment, token.next!);
     } else {
       if (varFinalOrConst != null && !name.isSynthetic) {
         if (optional("const", varFinalOrConst)) {
@@ -2905,14 +2907,14 @@
                   .withArguments(name.lexeme));
         }
       }
-      listener.handleNoFieldInitializer(token.next);
+      listener.handleNoFieldInitializer(token.next!);
     }
     return token;
   }
 
   Token parseVariableInitializerOpt(Token token) {
-    if (optional('=', token.next)) {
-      Token assignment = token.next;
+    if (optional('=', token.next!)) {
+      Token assignment = token.next!;
       listener.beginVariableInitializer(assignment);
       token = parseExpression(assignment);
       listener.endVariableInitializer(assignment);
@@ -2923,8 +2925,8 @@
   }
 
   Token parseInitializersOpt(Token token) {
-    if (optional(':', token.next)) {
-      return parseInitializers(token.next);
+    if (optional(':', token.next!)) {
+      return parseInitializers(token.next!);
     } else {
       listener.handleNoInitializers();
       return token;
@@ -2947,14 +2949,14 @@
     while (true) {
       token = parseInitializer(next);
       ++count;
-      next = token.next;
+      next = token.next!;
       if (!optional(',', next)) {
         // Recovery: Found an identifier which could be
         // 1) missing preceding `,` thus it's another initializer, or
         // 2) missing preceding `;` thus it's a class member, or
         // 3) missing preceding '{' thus it's a statement
         if (optional('assert', next)) {
-          next = next.next;
+          next = next.next!;
           if (!optional('(', next)) {
             break;
           }
@@ -2964,16 +2966,16 @@
           break;
         } else {
           if (optional('this', next)) {
-            next = next.next;
+            next = next.next!;
             if (!optional('.', next)) {
               break;
             }
-            next = next.next;
+            next = next.next!;
             if (!next.isIdentifier && !optional('assert', next)) {
               break;
             }
           }
-          next = next.next;
+          next = next.next!;
           if (!optional('=', next)) {
             break;
           }
@@ -2987,7 +2989,7 @@
       }
     }
     mayParseFunctionExpressions = old;
-    listener.endInitializers(count, begin, token.next);
+    listener.endInitializers(count, begin, token.next!);
     return token;
   }
 
@@ -3003,21 +3005,21 @@
   /// ;
   /// ```
   Token parseInitializer(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     listener.beginInitializer(next);
     Token beforeExpression = token;
     if (optional('assert', next)) {
       token = parseAssert(token, Assert.Initializer);
-      listener.endInitializer(token.next);
+      listener.endInitializer(token.next!);
       return token;
     } else if (optional('super', next)) {
       return parseSuperInitializerExpression(token);
     } else if (optional('this', next)) {
       token = next;
-      next = token.next;
+      next = token.next!;
       if (optional('.', next)) {
         token = next;
-        next = token.next;
+        next = token.next!;
         if (next.isIdentifier) {
           token = next;
         } else {
@@ -3025,14 +3027,14 @@
           token = insertSyntheticIdentifier(
               token, IdentifierContext.fieldInitializer);
         }
-        next = token.next;
+        next = token.next!;
         if (optional('=', next)) {
           return parseInitializerExpressionRest(beforeExpression);
         }
       }
       if (optional('(', next)) {
         token = parseInitializerExpressionRest(beforeExpression);
-        next = token.next;
+        next = token.next!;
         if (optional('{', next) || optional('=>', next)) {
           reportRecoverableError(
               next, codes.messageRedirectingConstructorWithBody);
@@ -3046,12 +3048,12 @@
         reportRecoverableError(
             next, codes.templateExpectedButGot.withArguments('.'));
         rewriter.insertSyntheticToken(token, TokenType.PERIOD);
-        token = rewriter.insertSyntheticIdentifier(token.next);
-        next = token.next;
+        token = rewriter.insertSyntheticIdentifier(token.next!);
+        next = token.next!;
       }
       // Fall through to recovery
     } else if (next.isIdentifier) {
-      Token next2 = next.next;
+      Token next2 = next.next!;
       if (optional('=', next2)) {
         return parseInitializerExpressionRest(token);
       }
@@ -3092,31 +3094,31 @@
   ///   'super' ('.' identifier)? arguments ;
   /// ```
   Token parseSuperInitializerExpression(final Token start) {
-    Token token = start.next;
+    Token token = start.next!;
     assert(optional('super', token));
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('.', next)) {
       token = next;
-      next = token.next;
+      next = token.next!;
       if (next.kind != IDENTIFIER_TOKEN) {
         next = IdentifierContext.expressionContinuation
             .ensureIdentifier(token, this);
       }
       token = next;
-      next = token.next;
+      next = token.next!;
     }
     if (!optional('(', next)) {
       // Recovery
       if (optional('?.', next)) {
         // An error for `super?.` is reported in parseSuperExpression.
         token = next;
-        next = token.next;
+        next = token.next!;
         if (!next.isIdentifier) {
           // Insert a synthetic identifier but don't report another error.
           next = rewriter.insertSyntheticIdentifier(token);
         }
         token = next;
-        next = token.next;
+        next = token.next!;
       }
       if (optional('=', next)) {
         if (optional('super', token)) {
@@ -3136,7 +3138,7 @@
 
   Token parseInitializerExpressionRest(Token token) {
     token = parseExpression(token);
-    listener.endInitializer(token.next);
+    listener.endInitializer(token.next!);
     return token;
   }
 
@@ -3147,9 +3149,9 @@
   /// a default error message instead.
   Token ensureBlock(
       Token token,
-      codes.Template<codes.Message Function(Token token)> template,
-      String missingBlockName) {
-    Token next = token.next;
+      codes.Template<codes.Message Function(Token token)>? template,
+      String? missingBlockName) {
+    Token next = token.next!;
     if (optional('{', next)) return next;
     if (template == null) {
       if (missingBlockName == null) {
@@ -3171,9 +3173,10 @@
   }
 
   Token insertBlock(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     BeginToken beginGroup = rewriter.insertToken(token,
-        new SyntheticBeginToken(TokenType.OPEN_CURLY_BRACKET, next.offset));
+            new SyntheticBeginToken(TokenType.OPEN_CURLY_BRACKET, next.offset))
+        as BeginToken;
     Token endGroup = rewriter.insertToken(beginGroup,
         new SyntheticToken(TokenType.CLOSE_CURLY_BRACKET, next.offset));
     beginGroup.endGroup = endGroup;
@@ -3184,14 +3187,14 @@
   /// Otherwise, report an error and return the closing parenthesis
   /// associated with the specified open parenthesis.
   Token ensureCloseParen(Token token, Token openParen) {
-    Token next = token.next;
+    Token next = token.next!;
     if (optional(')', next)) {
       return next;
     }
-    if (openParen.endGroup.isSynthetic) {
+    if (openParen.endGroup!.isSynthetic) {
       // Scanner has already reported a missing `)` error,
       // but placed the `)` in the wrong location, so move it.
-      return rewriter.moveSynthetic(token, openParen.endGroup);
+      return rewriter.moveSynthetic(token, openParen.endGroup!);
     }
 
     // TODO(danrubel): Pass in context for better error message.
@@ -3201,13 +3204,13 @@
     // Scanner guarantees a closing parenthesis
     // TODO(danrubel): Improve recovery by having callers parse tokens
     // between `token` and `openParen.endGroup`.
-    return openParen.endGroup;
+    return openParen.endGroup!;
   }
 
   /// If the next token is a colon, return it. Otherwise, report an
   /// error, insert a synthetic colon, and return the inserted colon.
   Token ensureColon(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     if (optional(':', next)) return next;
     codes.Message message = codes.templateExpectedButGot.withArguments(':');
     Token newToken = new SyntheticToken(TokenType.COLON, next.charOffset);
@@ -3218,7 +3221,7 @@
   /// then insert a synthetic literal string.
   /// Call `parseLiteralString` and return the result.
   Token ensureLiteralString(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     if (!identical(next.kind, STRING_TOKEN)) {
       codes.Message message = codes.templateExpectedString.withArguments(next);
       Token newToken = new SyntheticStringToken(
@@ -3235,7 +3238,7 @@
     // TODO(danrubel): Once all expect(';'...) call sites have been converted
     // to use this method, remove similar semicolon recovery code
     // from the handleError method in element_listener.dart.
-    Token next = token.next;
+    Token next = token.next!;
     if (optional(';', next)) return next;
 
     // Find a token on the same line as where the ';' should be inserted.
@@ -3249,14 +3252,14 @@
   /// Report an error at the token after [token] that has the given [message].
   /// Insert the [newToken] after [token] and return [newToken].
   Token rewriteAndRecover(Token token, codes.Message message, Token newToken) {
-    reportRecoverableError(token.next, message);
+    reportRecoverableError(token.next!, message);
     return rewriter.insertToken(token, newToken);
   }
 
   /// Replace the token after [token] with `[` followed by `]`
   /// and return [token].
   Token rewriteSquareBrackets(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('[]', next));
     Token replacement;
     if (next.isSynthetic) {
@@ -3277,9 +3280,9 @@
   /// Report the given token as unexpected and return the next token if the next
   /// token is one of the [expectedNext], otherwise just return the given token.
   Token skipUnexpectedTokenOpt(Token token, List<String> expectedNext) {
-    Token next = token.next;
+    Token next = token.next!;
     if (next.keyword == null) {
-      final String nextValue = next.next.stringValue;
+      final String? nextValue = next.next!.stringValue;
       for (String expectedValue in expectedNext) {
         if (identical(nextValue, expectedValue)) {
           reportRecoverableErrorWithToken(next, codes.templateUnexpectedToken);
@@ -3291,10 +3294,10 @@
   }
 
   Token parseNativeClause(Token token) {
-    Token nativeToken = token = token.next;
+    Token nativeToken = token = token.next!;
     assert(optional('native', nativeToken));
     bool hasName = false;
-    if (token.next.kind == STRING_TOKEN) {
+    if (token.next!.kind == STRING_TOKEN) {
       hasName = true;
       token = parseLiteralString(token);
     }
@@ -3316,17 +3319,17 @@
   /// ;
   /// ```
   Token parseClassOrMixinOrExtensionBody(
-      Token token, DeclarationKind kind, String enclosingDeclarationName) {
-    Token begin = token = token.next;
+      Token token, DeclarationKind kind, String? enclosingDeclarationName) {
+    Token begin = token = token.next!;
     assert(optional('{', token));
     listener.beginClassOrMixinBody(kind, token);
     int count = 0;
-    while (notEofOrValue('}', token.next)) {
+    while (notEofOrValue('}', token.next!)) {
       token = parseClassOrMixinOrExtensionMemberImpl(
           token, kind, enclosingDeclarationName);
       ++count;
     }
-    token = token.next;
+    token = token.next!;
     assert(token.isEof || optional('}', token));
     listener.endClassOrMixinBody(kind, count, begin, token);
     return token;
@@ -3335,7 +3338,7 @@
   bool isUnaryMinus(Token token) =>
       token.kind == IDENTIFIER_TOKEN &&
       token.lexeme == 'unary' &&
-      optional('-', token.next);
+      optional('-', token.next!);
 
   /// Parse a class member.
   ///
@@ -3346,7 +3349,7 @@
   Token parseClassMember(Token token, String className) {
     return parseClassOrMixinOrExtensionMemberImpl(
             syntheticPreviousToken(token), DeclarationKind.Class, className)
-        .next;
+        .next!;
   }
 
   /// Parse a mixin member.
@@ -3358,7 +3361,7 @@
   Token parseMixinMember(Token token, String mixinName) {
     return parseClassOrMixinOrExtensionMemberImpl(
             syntheticPreviousToken(token), DeclarationKind.Mixin, mixinName)
-        .next;
+        .next!;
   }
 
   /// Parse an extension member.
@@ -3370,7 +3373,7 @@
   Token parseExtensionMember(Token token, String extensionName) {
     return parseClassOrMixinOrExtensionMemberImpl(syntheticPreviousToken(token),
             DeclarationKind.Extension, extensionName)
-        .next;
+        .next!;
   }
 
   bool isReservedKeyword(Token token) {
@@ -3379,7 +3382,7 @@
   }
 
   bool indicatesMethodOrField(Token token) {
-    String value = token.stringValue;
+    String? value = token.stringValue;
     if (identical(value, ';') ||
         identical(value, '=') ||
         identical(value, '(') ||
@@ -3409,59 +3412,59 @@
   /// ;
   /// ```
   Token parseClassOrMixinOrExtensionMemberImpl(
-      Token token, DeclarationKind kind, String enclosingDeclarationName) {
+      Token token, DeclarationKind kind, String? enclosingDeclarationName) {
     Token beforeStart = token = parseMetadataStar(token);
 
-    Token skippedNonLateLate;
+    Token? skippedNonLateLate;
 
-    if (_isUseOfLateInNonNNBD(token.next)) {
-      skippedNonLateLate = token.next;
+    if (_isUseOfLateInNonNNBD(token.next!)) {
+      skippedNonLateLate = token.next!;
       reportRecoverableErrorWithToken(
           skippedNonLateLate, codes.templateUnexpectedModifierInNonNnbd);
-      token = token.next;
+      token = token.next!;
       beforeStart = token;
     }
 
-    Token covariantToken;
-    Token abstractToken;
-    Token externalToken;
-    Token lateToken;
-    Token staticToken;
-    Token varFinalOrConst;
+    Token? covariantToken;
+    Token? abstractToken;
+    Token? externalToken;
+    Token? lateToken;
+    Token? staticToken;
+    Token? varFinalOrConst;
 
-    Token next = token.next;
+    Token next = token.next!;
     if (isModifier(next)) {
       if (optional('external', next)) {
         externalToken = token = next;
-        next = token.next;
+        next = token.next!;
       } else if (optional('abstract', next)) {
         abstractToken = token = next;
-        next = token.next;
+        next = token.next!;
       }
       if (isModifier(next)) {
         if (optional('static', next)) {
           staticToken = token = next;
-          next = token.next;
+          next = token.next!;
         } else if (optional('covariant', next)) {
           covariantToken = token = next;
-          next = token.next;
+          next = token.next!;
         }
         if (isModifier(next)) {
           if (optional('final', next)) {
             varFinalOrConst = token = next;
-            next = token.next;
+            next = token.next!;
           } else if (optional('var', next)) {
             varFinalOrConst = token = next;
-            next = token.next;
+            next = token.next!;
           } else if (optional('const', next) && covariantToken == null) {
             varFinalOrConst = token = next;
-            next = token.next;
+            next = token.next!;
           } else if (optional('late', next)) {
             lateToken = token = next;
-            next = token.next;
+            next = token.next!;
             if (isModifier(next) && optional('final', next)) {
               varFinalOrConst = token = next;
-              next = token.next;
+              next = token.next!;
             }
           }
           if (isModifier(next)) {
@@ -3474,7 +3477,7 @@
               ..abstractToken = abstractToken;
 
             token = context.parseClassMemberModifiers(token);
-            next = token.next;
+            next = token.next!;
 
             covariantToken = context.covariantToken;
             externalToken = context.externalToken;
@@ -3482,8 +3485,6 @@
             staticToken = context.staticToken;
             varFinalOrConst = context.varFinalOrConst;
             abstractToken = context.abstractToken;
-
-            context = null;
           }
         }
       }
@@ -3504,26 +3505,26 @@
         /*required = */ false,
         /* inDeclaration = */ true);
     token = typeInfo.skipType(token);
-    next = token.next;
+    next = token.next!;
 
-    Token getOrSet;
+    Token? getOrSet;
     bool nameIsRecovered = false;
     if (next.type != TokenType.IDENTIFIER) {
-      String value = next.stringValue;
+      String? value = next.stringValue;
       if (identical(value, 'get') || identical(value, 'set')) {
-        if (next.next.isIdentifier) {
+        if (next.next!.isIdentifier) {
           getOrSet = token = next;
-          next = token.next;
-        } else if (isReservedKeyword(next.next) &&
-            indicatesMethodOrField(next.next.next)) {
+          next = token.next!;
+        } else if (isReservedKeyword(next.next!) &&
+            indicatesMethodOrField(next.next!.next!)) {
           // Recovery: Getter or setter followed by a reserved word (name).
           getOrSet = token = next;
-          next = token.next;
+          next = token.next!;
           nameIsRecovered = true;
         }
         // Fall through to continue parsing `get` or `set` as an identifier.
       } else if (identical(value, 'factory')) {
-        Token next2 = next.next;
+        Token next2 = next.next!;
         if (next2.isIdentifier || next2.isModifier) {
           if (beforeType != token) {
             reportRecoverableError(token, codes.messageTypeBeforeFactory);
@@ -3539,7 +3540,7 @@
         }
         // Fall through to continue parsing `factory` as an identifier.
       } else if (identical(value, 'operator')) {
-        Token next2 = next.next;
+        Token next2 = next.next!;
         TypeParamOrArgInfo typeParam = computeTypeParamOrArg(next);
         // `operator` can be used as an identifier as in
         // `int operator<T>()` or `int operator = 2`
@@ -3555,7 +3556,7 @@
               beforeType,
               typeInfo,
               getOrSet,
-              token.next,
+              token.next!,
               kind,
               enclosingDeclarationName,
               nameIsRecovered);
@@ -3591,7 +3592,7 @@
               beforeType,
               typeInfo,
               getOrSet,
-              token.next,
+              token.next!,
               kind,
               enclosingDeclarationName,
               nameIsRecovered);
@@ -3602,7 +3603,7 @@
       } else if (!next.isIdentifier ||
           (identical(value, 'typedef') &&
               token == beforeStart &&
-              next.next.isIdentifier)) {
+              next.next!.isIdentifier)) {
         if (abstractToken != null) {
           reportRecoverableError(
               abstractToken, codes.messageAbstractClassMember);
@@ -3624,9 +3625,9 @@
             enclosingDeclarationName);
       }
     } else if (typeInfo == noType && varFinalOrConst == null) {
-      Token next2 = next.next;
+      Token next2 = next.next!;
       if (next2.isUserDefinableOperator && next2.endGroup == null) {
-        String value = next2.next.stringValue;
+        String? value = next2.next!.stringValue;
         if (identical(value, '(') ||
             identical(value, '{') ||
             identical(value, '=>')) {
@@ -3644,21 +3645,21 @@
               enclosingDeclarationName);
         }
       } else if (isReservedKeyword(next2) &&
-          indicatesMethodOrField(next2.next)) {
+          indicatesMethodOrField(next2.next!)) {
         // Recovery: Use the reserved keyword despite that not being legal.
         typeInfo = computeType(
             token,
             /*required = */ true,
             /* inDeclaration = */ true);
         token = typeInfo.skipType(token);
-        next = token.next;
+        next = token.next!;
         nameIsRecovered = true;
       }
     }
 
     // At this point, token is before the name, and next is the name
-    next = next.next;
-    String value = next.stringValue;
+    next = next.next!;
+    String? value = next.stringValue;
     if (getOrSet != null ||
         identical(value, '(') ||
         identical(value, '{') ||
@@ -3676,7 +3677,7 @@
           beforeType,
           typeInfo,
           getOrSet,
-          token.next,
+          token.next!,
           kind,
           enclosingDeclarationName,
           nameIsRecovered);
@@ -3695,7 +3696,7 @@
           varFinalOrConst,
           beforeType,
           typeInfo,
-          token.next,
+          token.next!,
           kind,
           enclosingDeclarationName,
           nameIsRecovered);
@@ -3706,18 +3707,18 @@
 
   Token parseMethod(
       Token beforeStart,
-      Token abstractToken,
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       Token beforeType,
       TypeInfo typeInfo,
-      Token getOrSet,
+      Token? getOrSet,
       Token name,
       DeclarationKind kind,
-      String enclosingDeclarationName,
+      String? enclosingDeclarationName,
       bool nameIsRecovered) {
     if (abstractToken != null) {
       reportRecoverableError(abstractToken, codes.messageAbstractClassMember);
@@ -3728,7 +3729,7 @@
     }
     bool isOperator = false;
     if (getOrSet == null && optional('operator', name)) {
-      Token operator = name.next;
+      Token operator = name.next!;
       if (operator.isOperator ||
           identical(operator.kind, EQ_EQ_EQ_TOKEN) ||
           identical(operator.kind, BANG_EQ_EQ_TOKEN) ||
@@ -3800,13 +3801,13 @@
       token = parseMethodTypeVar(token);
     } else {
       isConsideredGetter = optional("get", getOrSet);
-      listener.handleNoTypeVariables(token.next);
+      listener.handleNoTypeVariables(token.next!);
 
       // If it becomes considered a constructor below, don't consider it a
       // getter now (this also enforces parenthesis (and thus parameters)).
       if (hasQualifiedName) {
         isConsideredGetter = false;
-      } else if (isConsideredGetter && optional(':', token.next)) {
+      } else if (isConsideredGetter && optional(':', token.next!)) {
         isConsideredGetter = false;
       } else if (isConsideredGetter &&
           name.lexeme == enclosingDeclarationName) {
@@ -3816,7 +3817,7 @@
     }
 
     Token beforeParam = token;
-    Token beforeInitializers = parseGetterOrFormalParameters(
+    Token? beforeInitializers = parseGetterOrFormalParameters(
         token,
         name,
         isConsideredGetter,
@@ -3831,12 +3832,12 @@
     if (token == beforeInitializers) beforeInitializers = null;
 
     AsyncModifier savedAsyncModifier = asyncState;
-    Token asyncToken = token.next;
+    Token asyncToken = token.next!;
     token = parseAsyncModifierOpt(token);
     if (getOrSet != null && !inPlainSync && optional("set", getOrSet)) {
       reportRecoverableError(asyncToken, codes.messageSetterNotSync);
     }
-    final Token bodyStart = token.next;
+    final Token bodyStart = token.next!;
     if (externalToken != null) {
       if (!optional(';', bodyStart)) {
         reportRecoverableError(bodyStart, codes.messageExternalMethodWithBody);
@@ -3852,7 +3853,7 @@
     asyncState = savedAsyncModifier;
 
     bool isConstructor = false;
-    if (optional('.', name.next) || beforeInitializers != null) {
+    if (optional('.', name.next!) || beforeInitializers != null) {
       // This is only legal for constructors.
       isConstructor = true;
     } else if (name.lexeme == enclosingDeclarationName) {
@@ -3885,33 +3886,32 @@
       }
       if (typeInfo != noType) {
         reportRecoverableError(
-            beforeType.next, codes.messageConstructorWithReturnType);
+            beforeType.next!, codes.messageConstructorWithReturnType);
       }
       if (beforeInitializers != null && externalToken != null) {
-        reportRecoverableError(beforeInitializers.next,
+        reportRecoverableError(beforeInitializers.next!,
             codes.messageExternalConstructorWithInitializer);
       }
 
       switch (kind) {
         case DeclarationKind.Class:
           // TODO(danrubel): Remove getOrSet from constructor events
-          listener.endClassConstructor(getOrSet, beforeStart.next,
-              beforeParam.next, beforeInitializers?.next, token);
+          listener.endClassConstructor(getOrSet, beforeStart.next!,
+              beforeParam.next!, beforeInitializers?.next, token);
           break;
         case DeclarationKind.Mixin:
           reportRecoverableError(name, codes.messageMixinDeclaresConstructor);
-          listener.endMixinConstructor(getOrSet, beforeStart.next,
-              beforeParam.next, beforeInitializers?.next, token);
+          listener.endMixinConstructor(getOrSet, beforeStart.next!,
+              beforeParam.next!, beforeInitializers?.next, token);
           break;
         case DeclarationKind.Extension:
           reportRecoverableError(
               name, codes.messageExtensionDeclaresConstructor);
-          listener.endExtensionConstructor(getOrSet, beforeStart.next,
-              beforeParam.next, beforeInitializers?.next, token);
+          listener.endExtensionConstructor(getOrSet, beforeStart.next!,
+              beforeParam.next!, beforeInitializers?.next, token);
           break;
         case DeclarationKind.TopLevel:
           throw "Internal error: TopLevel constructor.";
-          break;
       }
     } else {
       //
@@ -3924,35 +3924,34 @@
       switch (kind) {
         case DeclarationKind.Class:
           // TODO(danrubel): Remove beginInitializers token from method events
-          listener.endClassMethod(getOrSet, beforeStart.next, beforeParam.next,
-              beforeInitializers?.next, token);
+          listener.endClassMethod(getOrSet, beforeStart.next!,
+              beforeParam.next!, beforeInitializers?.next, token);
           break;
         case DeclarationKind.Mixin:
-          listener.endMixinMethod(getOrSet, beforeStart.next, beforeParam.next,
-              beforeInitializers?.next, token);
+          listener.endMixinMethod(getOrSet, beforeStart.next!,
+              beforeParam.next!, beforeInitializers?.next, token);
           break;
         case DeclarationKind.Extension:
           if (optional(';', bodyStart) && externalToken == null) {
-            reportRecoverableError(isOperator ? name.next : name,
+            reportRecoverableError(isOperator ? name.next! : name,
                 codes.messageExtensionDeclaresAbstractMember);
           }
-          listener.endExtensionMethod(getOrSet, beforeStart.next,
-              beforeParam.next, beforeInitializers?.next, token);
+          listener.endExtensionMethod(getOrSet, beforeStart.next!,
+              beforeParam.next!, beforeInitializers?.next, token);
           break;
         case DeclarationKind.TopLevel:
           throw "Internal error: TopLevel method.";
-          break;
       }
     }
     return token;
   }
 
   Token parseFactoryMethod(Token token, DeclarationKind kind, Token beforeStart,
-      Token externalToken, Token staticOrCovariant, Token varFinalOrConst) {
-    Token factoryKeyword = token = token.next;
+      Token? externalToken, Token? staticOrCovariant, Token? varFinalOrConst) {
+    Token factoryKeyword = token = token.next!;
     assert(optional('factory', factoryKeyword));
 
-    if (!isValidTypeReference(token.next)) {
+    if (!isValidTypeReference(token.next!)) {
       // Recovery
       ModifierRecoveryContext context = new ModifierRecoveryContext(this)
         ..externalToken = externalToken
@@ -3964,8 +3963,6 @@
       externalToken = context.externalToken;
       staticOrCovariant = context.staticToken ?? context.covariantToken;
       varFinalOrConst = context.varFinalOrConst;
-
-      context = null;
     }
 
     if (staticOrCovariant != null) {
@@ -3984,9 +3981,9 @@
         token, IdentifierContext.methodDeclarationContinuation);
     token = parseMethodTypeVar(token);
     token = parseFormalParametersRequiredOpt(token, MemberKind.Factory);
-    Token asyncToken = token.next;
+    Token asyncToken = token.next!;
     token = parseAsyncModifierOpt(token);
-    Token next = token.next;
+    Token next = token.next!;
     if (!inPlainSync) {
       reportRecoverableError(asyncToken, codes.messageFactoryNotSync);
     }
@@ -4016,31 +4013,32 @@
     }
     switch (kind) {
       case DeclarationKind.Class:
-        listener.endClassFactoryMethod(beforeStart.next, factoryKeyword, token);
+        listener.endClassFactoryMethod(
+            beforeStart.next!, factoryKeyword, token);
         break;
       case DeclarationKind.Mixin:
         reportRecoverableError(
             factoryKeyword, codes.messageMixinDeclaresConstructor);
-        listener.endMixinFactoryMethod(beforeStart.next, factoryKeyword, token);
+        listener.endMixinFactoryMethod(
+            beforeStart.next!, factoryKeyword, token);
         break;
       case DeclarationKind.Extension:
         reportRecoverableError(
             factoryKeyword, codes.messageExtensionDeclaresConstructor);
         listener.endExtensionFactoryMethod(
-            beforeStart.next, factoryKeyword, token);
+            beforeStart.next!, factoryKeyword, token);
         break;
       case DeclarationKind.TopLevel:
         throw "Internal error: TopLevel factory.";
-        break;
     }
     return token;
   }
 
   Token parseOperatorName(Token token) {
     Token beforeToken = token;
-    token = token.next;
+    token = token.next!;
     assert(optional('operator', token));
-    Token next = token.next;
+    Token next = token.next!;
     if (next.isUserDefinableOperator) {
       if (computeTypeParamOrArg(token) != noTypeParamOrArg) {
         // `operator` is being used as an identifier.
@@ -4056,7 +4054,7 @@
     } else if (isUnaryMinus(next)) {
       // Recovery
       reportRecoverableErrorWithToken(next, codes.templateUnexpectedToken);
-      next = next.next;
+      next = next.next!;
       listener.handleOperatorName(token, next);
       return next;
     } else {
@@ -4074,12 +4072,12 @@
   }
 
   Token parseFunctionExpression(Token token) {
-    Token beginToken = token.next;
+    Token beginToken = token.next!;
     listener.beginFunctionExpression(beginToken);
     token = parseFormalParametersRequiredOpt(token, MemberKind.Local);
     token = parseAsyncOptBody(
         token, /* ofFunctionExpression = */ true, /* allowAbstract = */ false);
-    listener.endFunctionExpression(beginToken, token.next);
+    listener.endFunctionExpression(beginToken, token.next!);
     return token;
   }
 
@@ -4091,10 +4089,10 @@
       TypeParamOrArgInfo typeParam,
       IdentifierContext context) {
     Token formals = typeParam.parseVariables(name, this);
-    listener.beginNamedFunctionExpression(start.next);
+    listener.beginNamedFunctionExpression(start.next!);
     typeInfo.parseType(start, this);
     return parseNamedFunctionRest(
-        beforeName, start.next, formals, /* isFunctionExpression = */ true);
+        beforeName, start.next!, formals, /* isFunctionExpression = */ true);
   }
 
   /// Parses the rest of a named function declaration starting from its [name]
@@ -4115,14 +4113,14 @@
   /// - Return type.
   Token parseNamedFunctionRest(
       Token beforeName, Token begin, Token formals, bool isFunctionExpression) {
-    Token token = beforeName.next;
+    Token token = beforeName.next!;
     listener.beginFunctionName(token);
     token =
         ensureIdentifier(beforeName, IdentifierContext.localFunctionDeclaration)
-            .next;
+            .next!;
     if (isFunctionExpression) {
       reportRecoverableError(
-          beforeName.next, codes.messageNamedFunctionExpression);
+          beforeName.next!, codes.messageNamedFunctionExpression);
     }
     listener.endFunctionName(begin, token);
     token = parseFormalParametersRequiredOpt(formals, MemberKind.Local);
@@ -4153,7 +4151,7 @@
     return token;
   }
 
-  Token parseConstructorReference(Token token, [TypeParamOrArgInfo typeArg]) {
+  Token parseConstructorReference(Token token, [TypeParamOrArgInfo? typeArg]) {
     Token start =
         ensureIdentifier(token, IdentifierContext.constructorReference);
     listener.beginConstructorReference(start);
@@ -4161,21 +4159,21 @@
         start, IdentifierContext.constructorReferenceContinuation);
     typeArg ??= computeTypeParamOrArg(token);
     token = typeArg.parseArguments(token, this);
-    Token period = null;
-    if (optional('.', token.next)) {
-      period = token.next;
+    Token? period = null;
+    if (optional('.', token.next!)) {
+      period = token.next!;
       token = ensureIdentifier(period,
           IdentifierContext.constructorReferenceContinuationAfterTypeArguments);
     } else {
       listener.handleNoConstructorReferenceContinuationAfterTypeArguments(
-          token.next);
+          token.next!);
     }
-    listener.endConstructorReference(start, period, token.next);
+    listener.endConstructorReference(start, period, token.next!);
     return token;
   }
 
   Token parseRedirectingFactoryBody(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional('=', token));
     listener.beginRedirectingFactoryBody(token);
     Token equals = token;
@@ -4188,22 +4186,22 @@
   Token skipFunctionBody(Token token, bool isExpression, bool allowAbstract) {
     assert(!isExpression);
     token = skipAsyncModifier(token);
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('native', next)) {
       Token nativeToken = next;
       // TODO(danrubel): skip the native clause rather than parsing it
       // or remove this code completely when we remove support
       // for the `native` clause.
       token = parseNativeClause(token);
-      next = token.next;
+      next = token.next!;
       if (optional(';', next)) {
         listener.handleNativeFunctionBodySkipped(nativeToken, next);
-        return token.next;
+        return token.next!;
       }
       listener.handleNativeFunctionBodyIgnored(nativeToken, next);
       // Fall through to recover and skip function body
     }
-    String value = next.stringValue;
+    String? value = next.stringValue;
     if (identical(value, ';')) {
       token = next;
       if (!allowAbstract) {
@@ -4215,8 +4213,8 @@
       // There ought to be a semicolon following the expression, but we check
       // before advancing in order to be consistent with the way the method
       // [parseFunctionBody] recovers when the semicolon is missing.
-      if (optional(';', token.next)) {
-        token = token.next;
+      if (optional(';', token.next!)) {
+        token = token.next!;
       }
       listener.handleFunctionBodySkipped(token, /* isExpressionBody = */ true);
     } else if (identical(value, '=')) {
@@ -4226,8 +4224,8 @@
       // There ought to be a semicolon following the expression, but we check
       // before advancing in order to be consistent with the way the method
       // [parseFunctionBody] recovers when the semicolon is missing.
-      if (optional(';', token.next)) {
-        token = token.next;
+      if (optional(';', token.next!)) {
+        token = token.next!;
       }
       listener.handleFunctionBodySkipped(token, /* isExpressionBody = */ true);
     } else {
@@ -4245,11 +4243,11 @@
   /// It's an error if there's no function body unless [allowAbstract] is true.
   Token parseFunctionBody(
       Token token, bool ofFunctionExpression, bool allowAbstract) {
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('native', next)) {
       Token nativeToken = next;
       token = parseNativeClause(token);
-      next = token.next;
+      next = token.next!;
       if (optional(';', next)) {
         listener.handleNativeFunctionBody(nativeToken, next);
         return next;
@@ -4270,7 +4268,7 @@
       // Recover from a bad factory method.
       reportRecoverableError(next, codes.messageExpectedBody);
       next = rewriter.insertToken(
-          next, new SyntheticToken(TokenType.FUNCTION, next.next.charOffset));
+          next, new SyntheticToken(TokenType.FUNCTION, next.next!.charOffset));
       Token begin = next;
       token = parseExpression(next);
       if (!ofFunctionExpression) {
@@ -4288,21 +4286,21 @@
       // If `return` used instead of `=>`, then report an error and continue
       if (optional('return', next)) {
         reportRecoverableError(next, codes.messageExpectedBody);
-        next = rewriter.insertToken(
-            next, new SyntheticToken(TokenType.FUNCTION, next.next.charOffset));
+        next = rewriter.insertToken(next,
+            new SyntheticToken(TokenType.FUNCTION, next.next!.charOffset));
         return parseExpressionFunctionBody(next, ofFunctionExpression);
       }
       // If there is a stray simple identifier in the function expression
       // because the user is typing (e.g. `() asy => null;`)
       // then report an error, skip the token, and continue parsing.
-      if (next.isKeywordOrIdentifier && optional('=>', next.next)) {
+      if (next.isKeywordOrIdentifier && optional('=>', next.next!)) {
         reportRecoverableErrorWithToken(next, codes.templateUnexpectedToken);
-        return parseExpressionFunctionBody(next.next, ofFunctionExpression);
+        return parseExpressionFunctionBody(next.next!, ofFunctionExpression);
       }
-      if (next.isKeywordOrIdentifier && optional('{', next.next)) {
+      if (next.isKeywordOrIdentifier && optional('{', next.next!)) {
         reportRecoverableErrorWithToken(next, codes.templateUnexpectedToken);
         token = next;
-        begin = next = token.next;
+        begin = next = token.next!;
         // Fall through to parse the block.
       } else {
         token = ensureBlock(
@@ -4310,7 +4308,7 @@
             codes.templateExpectedFunctionBody,
             /* missingBlockName = */ null);
         listener.handleInvalidFunctionBody(token);
-        return token.endGroup;
+        return token.endGroup!;
       }
     }
 
@@ -4318,19 +4316,19 @@
     loopState = LoopState.OutsideLoop;
     listener.beginBlockFunctionBody(begin);
     token = next;
-    while (notEofOrValue('}', token.next)) {
-      Token startToken = token.next;
+    while (notEofOrValue('}', token.next!)) {
+      Token startToken = token.next!;
       token = parseStatement(token);
-      if (identical(token.next, startToken)) {
+      if (identical(token.next!, startToken)) {
         // No progress was made, so we report the current token as being invalid
         // and move forward.
         reportRecoverableError(
             token, codes.templateUnexpectedToken.withArguments(token));
-        token = token.next;
+        token = token.next!;
       }
       ++statementCount;
     }
-    token = token.next;
+    token = token.next!;
     assert(token.isEof || optional('}', token));
     listener.endBlockFunctionBody(statementCount, begin, token);
     loopState = savedLoopState;
@@ -4355,33 +4353,33 @@
   }
 
   Token skipAsyncModifier(Token token) {
-    String value = token.next.stringValue;
+    String? value = token.next!.stringValue;
     if (identical(value, 'async')) {
-      token = token.next;
-      value = token.next.stringValue;
+      token = token.next!;
+      value = token.next!.stringValue;
 
       if (identical(value, '*')) {
-        token = token.next;
+        token = token.next!;
       }
     } else if (identical(value, 'sync')) {
-      token = token.next;
-      value = token.next.stringValue;
+      token = token.next!;
+      value = token.next!.stringValue;
 
       if (identical(value, '*')) {
-        token = token.next;
+        token = token.next!;
       }
     }
     return token;
   }
 
   Token parseAsyncModifierOpt(Token token) {
-    Token async;
-    Token star;
+    Token? async;
+    Token? star;
     asyncState = AsyncModifier.Sync;
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('async', next)) {
       async = token = next;
-      next = token.next;
+      next = token.next!;
       if (optional('*', next)) {
         asyncState = AsyncModifier.AsyncStar;
         star = next;
@@ -4391,7 +4389,7 @@
       }
     } else if (optional('sync', next)) {
       async = token = next;
-      next = token.next;
+      next = token.next!;
       if (optional('*', next)) {
         asyncState = AsyncModifier.SyncStar;
         star = next;
@@ -4401,8 +4399,8 @@
       }
     }
     listener.handleAsyncModifier(async, star);
-    if (!inPlainSync && optional(';', token.next)) {
-      reportRecoverableError(token.next, codes.messageAbstractNotSync);
+    if (!inPlainSync && optional(';', token.next!)) {
+      reportRecoverableError(token.next!, codes.messageAbstractNotSync);
     }
     return token;
   }
@@ -4421,8 +4419,8 @@
   }
 
   Token parseStatementX(Token token) {
-    if (identical(token.next.kind, IDENTIFIER_TOKEN)) {
-      if (optional(':', token.next.next)) {
+    if (identical(token.next!.kind, IDENTIFIER_TOKEN)) {
+      if (optional(':', token.next!.next!)) {
         return parseLabeledStatement(token);
       }
       return parseExpressionStatementOrDeclarationAfterModifiers(
@@ -4433,15 +4431,15 @@
           /* typeInfo = */ null,
           /* onlyParseVariableDeclarationStart = */ false);
     }
-    final String value = token.next.stringValue;
+    final String? value = token.next!.stringValue;
     if (identical(value, '{')) {
       // The scanner ensures that `{` always has a closing `}`.
       return parseBlock(token, BlockKind.statement);
     } else if (identical(value, 'return')) {
       return parseReturnStatement(token);
     } else if (identical(value, 'var') || identical(value, 'final')) {
-      Token varOrFinal = token.next;
-      if (!isModifier(varOrFinal.next)) {
+      Token varOrFinal = token.next!;
+      if (!isModifier(varOrFinal.next!)) {
         return parseExpressionStatementOrDeclarationAfterModifiers(
             varOrFinal,
             token,
@@ -4453,8 +4451,9 @@
       return parseExpressionStatementOrDeclaration(token);
     } else if (identical(value, 'if')) {
       return parseIfStatement(token);
-    } else if (identical(value, 'await') && optional('for', token.next.next)) {
-      return parseForStatement(token.next, token.next);
+    } else if (identical(value, 'await') &&
+        optional('for', token.next!.next!)) {
+      return parseForStatement(token.next!, token.next!);
     } else if (identical(value, 'for')) {
       return parseForStatement(token, /* awaitToken = */ null);
     } else if (identical(value, 'rethrow')) {
@@ -4478,7 +4477,7 @@
     } else if (identical(value, 'yield')) {
       switch (asyncState) {
         case AsyncModifier.Sync:
-          if (optional(':', token.next.next)) {
+          if (optional(':', token.next!.next!)) {
             return parseLabeledStatement(token);
           }
           if (looksLikeYieldStatement(token)) {
@@ -4494,10 +4493,9 @@
           return parseYieldStatement(token);
 
         case AsyncModifier.Async:
-          reportRecoverableError(token.next, codes.messageYieldNotGenerator);
+          reportRecoverableError(token.next!, codes.messageYieldNotGenerator);
           return parseYieldStatement(token);
       }
-      throw "Internal error: Unknown asyncState: '$asyncState'.";
     } else if (identical(value, 'const')) {
       return parseExpressionStatementOrConstDeclaration(token);
     } else if (identical(value, 'await')) {
@@ -4511,13 +4509,13 @@
         // and parseAwaitExpression will report the error.
       }
       return parseExpressionStatement(token);
-    } else if (identical(value, 'set') && token.next.next.isIdentifier) {
+    } else if (identical(value, 'set') && token.next!.next!.isIdentifier) {
       // Recovery: invalid use of `set`
       reportRecoverableErrorWithToken(
-          token.next, codes.templateUnexpectedToken);
-      return parseStatementX(token.next);
-    } else if (token.next.isIdentifier) {
-      if (optional(':', token.next.next)) {
+          token.next!, codes.templateUnexpectedToken);
+      return parseStatementX(token.next!);
+    } else if (token.next!.isIdentifier) {
+      if (optional(':', token.next!.next!)) {
         return parseLabeledStatement(token);
       }
       return parseExpressionStatementOrDeclaration(token);
@@ -4532,12 +4530,12 @@
   /// ;
   /// ```
   Token parseYieldStatement(Token token) {
-    Token begin = token = token.next;
+    Token begin = token = token.next!;
     assert(optional('yield', token));
     listener.beginYieldStatement(begin);
-    Token starToken;
-    if (optional('*', token.next)) {
-      starToken = token = token.next;
+    Token? starToken;
+    if (optional('*', token.next!)) {
+      starToken = token = token.next!;
     }
     token = parseExpression(token);
     token = ensureSemicolon(token);
@@ -4563,10 +4561,10 @@
   /// ;
   /// ```
   Token parseReturnStatement(Token token) {
-    Token begin = token = token.next;
+    Token begin = token = token.next!;
     assert(optional('return', token));
     listener.beginReturnStatement(begin);
-    Token next = token.next;
+    Token next = token.next!;
     if (optional(';', next)) {
       listener.endReturnStatement(/* hasExpression = */ false, begin, next);
       return next;
@@ -4587,8 +4585,8 @@
   /// ;
   /// ```
   Token parseLabel(Token token) {
-    assert(token.next.isIdentifier);
-    token = ensureIdentifier(token, IdentifierContext.labelDeclaration).next;
+    assert(token.next!.isIdentifier);
+    token = ensureIdentifier(token, IdentifierContext.labelDeclaration).next!;
     assert(optional(':', token));
     listener.handleLabel(token);
     return token;
@@ -4600,15 +4598,15 @@
   /// ;
   /// ```
   Token parseLabeledStatement(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(next.isIdentifier);
-    assert(optional(':', next.next));
+    assert(optional(':', next.next!));
     int labelCount = 0;
     do {
       token = parseLabel(token);
-      next = token.next;
+      next = token.next!;
       labelCount++;
-    } while (next.isIdentifier && optional(':', next.next));
+    } while (next.isIdentifier && optional(':', next.next!));
     listener.beginLabeledStatement(next, labelCount);
     token = parseStatement(token);
     listener.endLabeledStatement(labelCount);
@@ -4641,20 +4639,20 @@
       // This happens in degenerate programs, for example, with a lot of nested
       // list literals. This is provoked by, for example, the language test
       // deep_nesting1_negative_test.
-      Token next = token.next;
+      Token next = token.next!;
       reportRecoverableError(next, codes.messageStackOverflow);
 
       // Recovery
-      Token endGroup = next.endGroup;
+      Token? endGroup = next.endGroup;
       if (endGroup != null) {
         while (!next.isEof && !identical(next, endGroup)) {
           token = next;
-          next = token.next;
+          next = token.next!;
         }
       } else {
         while (!isOneOf(next, const [')', ']', '}', ';'])) {
           token = next;
-          next = token.next;
+          next = token.next!;
         }
       }
       if (!token.isEof) {
@@ -4662,7 +4660,7 @@
         listener.handleIdentifier(token, IdentifierContext.expression);
       }
     } else {
-      token = optional('throw', token.next)
+      token = optional('throw', token.next!)
           ? parseThrowExpression(token, /* allowCascades = */ true)
           : parsePrecedenceExpression(
               token, ASSIGNMENT_PRECEDENCE, /* allowCascades = */ true);
@@ -4672,7 +4670,7 @@
   }
 
   Token parseExpressionWithoutCascade(Token token) {
-    return optional('throw', token.next)
+    return optional('throw', token.next!)
         ? parseThrowExpression(token, /* allowCascades = */ false)
         : parsePrecedenceExpression(
             token, ASSIGNMENT_PRECEDENCE, /* allowCascades = */ false);
@@ -4682,7 +4680,7 @@
     // We want to check if we can parse, not send events and permanently change
     // the token stream. Set it up so we can do that.
     Listener originalListener = listener;
-    TokenStreamRewriter originalRewriter = cachedRewriter;
+    TokenStreamRewriter? originalRewriter = cachedRewriter;
     NullListener nullListener = listener = new NullListener();
     UndoableTokenStreamRewriter undoableTokenStreamRewriter =
         new UndoableTokenStreamRewriter();
@@ -4691,8 +4689,8 @@
     bool isConditional = false;
 
     Token afterExpression1 = parseExpressionWithoutCascade(question);
-    if (!nullListener.hasErrors && optional(':', afterExpression1.next)) {
-      parseExpressionWithoutCascade(afterExpression1.next);
+    if (!nullListener.hasErrors && optional(':', afterExpression1.next!)) {
+      parseExpressionWithoutCascade(afterExpression1.next!);
       if (!nullListener.hasErrors) {
         // Now we know it's a conditional expression.
         isConditional = true;
@@ -4708,7 +4706,7 @@
   }
 
   Token parseConditionalExpressionRest(Token token) {
-    Token question = token = token.next;
+    Token question = token = token.next!;
     assert(optional('?', question));
     listener.beginConditionalExpression(token);
     token = parseExpressionWithoutCascade(token);
@@ -4725,8 +4723,8 @@
     assert(precedence <= SELECTOR_PRECEDENCE);
     token = parseUnaryExpression(token, allowCascades);
     Token bangToken = token;
-    if (optional('!', token.next)) {
-      bangToken = token.next;
+    if (optional('!', token.next!)) {
+      bangToken = token.next!;
     }
     TypeParamOrArgInfo typeArg = computeMethodTypeArguments(bangToken);
     if (typeArg != noTypeParamOrArg) {
@@ -4735,7 +4733,7 @@
         listener.handleNonNullAssertExpression(bangToken);
       }
       token = typeArg.parseArguments(bangToken, this);
-      assert(optional('(', token.next));
+      assert(optional('(', token.next!));
     }
 
     return _parsePrecedenceExpressionLoop(
@@ -4744,13 +4742,13 @@
 
   Token _parsePrecedenceExpressionLoop(int precedence, bool allowCascades,
       TypeParamOrArgInfo typeArg, Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     TokenType type = next.type;
     int tokenLevel = _computePrecedence(next);
     bool enteredLoop = false;
     for (int level = tokenLevel; level >= precedence; --level) {
       int lastBinaryExpressionLevel = -1;
-      Token lastCascade;
+      Token? lastCascade;
       while (identical(tokenLevel, level)) {
         enteredLoop = true;
         Token operator = next;
@@ -4766,15 +4764,15 @@
         } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) {
           // Right associative, so we recurse at the same precedence
           // level.
-          Token next = token.next;
-          token = optional('throw', next.next)
+          Token next = token.next!;
+          token = optional('throw', next.next!)
               ? parseThrowExpression(next, /* allowCascades = */ false)
               : parsePrecedenceExpression(next, level, allowCascades);
           listener.handleAssignmentExpression(operator);
         } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) {
           if ((identical(type, TokenType.PLUS_PLUS)) ||
               (identical(type, TokenType.MINUS_MINUS))) {
-            listener.handleUnaryPostfixAssignmentExpression(token.next);
+            listener.handleUnaryPostfixAssignmentExpression(token.next!);
             token = next;
           } else if (identical(type, TokenType.BANG)) {
             listener.handleNonNullAssertExpression(next);
@@ -4789,12 +4787,12 @@
             // unary expression isn't legal after a period, so we call
             // [parsePrimary] instead.
             token = parsePrimary(
-                token.next, IdentifierContext.expressionContinuation);
+                token.next!, IdentifierContext.expressionContinuation);
             listener.handleEndingBinaryExpression(operator);
 
             Token bangToken = token;
-            if (optional('!', token.next)) {
-              bangToken = token.next;
+            if (optional('!', token.next!)) {
+              bangToken = token.next!;
             }
             typeArg = computeMethodTypeArguments(bangToken);
             if (typeArg != noTypeParamOrArg) {
@@ -4803,7 +4801,7 @@
                 listener.handleNonNullAssertExpression(bangToken);
               }
               token = typeArg.parseArguments(bangToken, this);
-              assert(optional('(', token.next));
+              assert(optional('(', token.next!));
             }
           } else if (identical(type, TokenType.OPEN_PAREN) ||
               identical(type, TokenType.OPEN_SQUARE_BRACKET)) {
@@ -4819,12 +4817,12 @@
             token = parseArgumentOrIndexStar(
                 token, noTypeParamOrArg, /* checkedNullAware = */ false);
           } else if (identical(type, TokenType.BANG)) {
-            listener.handleNonNullAssertExpression(token.next);
+            listener.handleNonNullAssertExpression(token.next!);
             token = next;
           } else {
             // Recovery
             reportRecoverableErrorWithToken(
-                token.next, codes.templateUnexpectedToken);
+                token.next!, codes.templateUnexpectedToken);
             token = next;
           }
         } else if (identical(type, TokenType.IS)) {
@@ -4849,10 +4847,10 @@
           // Left associative, so we recurse at the next higher
           // precedence level.
           token =
-              parsePrecedenceExpression(token.next, level + 1, allowCascades);
+              parsePrecedenceExpression(token.next!, level + 1, allowCascades);
           listener.endBinaryExpression(operator);
         }
-        next = token.next;
+        next = token.next!;
         type = next.type;
         tokenLevel = _computePrecedence(next);
       }
@@ -4862,7 +4860,7 @@
             token, precedence, level, allowCascades, typeArg)) {
           // Recovered - try again at same level with the replacement token.
           level++;
-          next = token.next;
+          next = token.next!;
           type = next.type;
           tokenLevel = _computePrecedence(next);
         }
@@ -4884,8 +4882,8 @@
   bool _attemptPrecedenceLevelRecovery(Token token, int precedence,
       int currentLevel, bool allowCascades, TypeParamOrArgInfo typeArg) {
     // Attempt recovery.
-    assert(_token_recovery_replacements.containsKey(token.next.lexeme));
-    TokenType replacement = _token_recovery_replacements[token.next.lexeme];
+    assert(_token_recovery_replacements.containsKey(token.next!.lexeme));
+    TokenType replacement = _token_recovery_replacements[token.next!.lexeme]!;
     if (currentLevel >= 0) {
       // Check that the new precedence and currentLevel would have accepted this
       // replacement here.
@@ -4907,7 +4905,7 @@
     _currentlyRecovering = true;
     _recoverAtPrecedenceLevel = false;
     Listener originalListener = listener;
-    TokenStreamRewriter originalRewriter = cachedRewriter;
+    TokenStreamRewriter? originalRewriter = cachedRewriter;
     NullListener nullListener = listener = new NullListener();
     UndoableTokenStreamRewriter undoableTokenStreamRewriter =
         new UndoableTokenStreamRewriter();
@@ -4918,7 +4916,7 @@
         precedence, allowCascades, typeArg, token);
 
     if (!nullListener.hasErrors &&
-        isOneOfOrEof(afterExpression.next, const [';', ',', ')', '{', '}'])) {
+        isOneOfOrEof(afterExpression.next!, const [';', ',', ')', '{', '}'])) {
       // Seems good!
       acceptRecovery = true;
     }
@@ -4932,9 +4930,9 @@
     if (acceptRecovery) {
       // Report and redo recovery.
       reportRecoverableError(
-          token.next,
+          token.next!,
           codes.templateBinaryOperatorWrittenOut
-              .withArguments(token.next.lexeme, replacement.lexeme));
+              .withArguments(token.next!.lexeme, replacement.lexeme));
       rewriter.replaceNextTokenWithSyntheticToken(token, replacement);
       return true;
     }
@@ -4958,7 +4956,7 @@
     if (identical(type, TokenType.BANG)) {
       // The '!' has prefix precedence but here it's being used as a
       // postfix operator to assert the expression has a non-null value.
-      TokenType nextType = token.next.type;
+      TokenType nextType = token.next!.type;
       if (identical(nextType, TokenType.PERIOD) ||
           identical(nextType, TokenType.QUESTION) ||
           identical(nextType, TokenType.OPEN_PAREN) ||
@@ -4968,7 +4966,7 @@
       }
       return POSTFIX_PRECEDENCE;
     } else if (identical(type, TokenType.QUESTION) &&
-        optional('[', token.next)) {
+        optional('[', token.next!)) {
       // "?[" can be a null-aware bracket or a conditional. If it's a
       // null-aware bracket it has selector precedence.
       bool isConditional = canParseAsConditional(token);
@@ -4988,35 +4986,35 @@
   }
 
   Token parseCascadeExpression(Token token) {
-    Token cascadeOperator = token = token.next;
+    Token cascadeOperator = token = token.next!;
     assert(optional('..', cascadeOperator) || optional('?..', cascadeOperator));
     listener.beginCascade(cascadeOperator);
-    if (optional('[', token.next)) {
+    if (optional('[', token.next!)) {
       token = parseArgumentOrIndexStar(
           token, noTypeParamOrArg, /* checkedNullAware = */ false);
     } else {
       token = parseSend(token, IdentifierContext.expressionContinuation);
       listener.handleEndingBinaryExpression(cascadeOperator);
     }
-    Token next = token.next;
+    Token next = token.next!;
     Token mark;
     do {
       mark = token;
       if (optional('.', next) || optional('?.', next)) {
         Token period = next;
         token = parseSend(next, IdentifierContext.expressionContinuation);
-        next = token.next;
+        next = token.next!;
         listener.handleEndingBinaryExpression(period);
       } else if (optional('!', next)) {
         listener.handleNonNullAssertExpression(next);
         token = next;
-        next = token.next;
+        next = token.next!;
       }
       TypeParamOrArgInfo typeArg = computeMethodTypeArguments(token);
       if (typeArg != noTypeParamOrArg) {
         // For example a(b)..<T>(c), where token is '<'.
         token = typeArg.parseArguments(token, this);
-        next = token.next;
+        next = token.next!;
         assert(optional('(', next));
       }
       TokenType nextType = next.type;
@@ -5029,7 +5027,7 @@
       }
       token = parseArgumentOrIndexStar(
           token, typeArg, /* checkedNullAware = */ false);
-      next = token.next;
+      next = token.next!;
     } while (!identical(mark, token));
 
     if (identical(next.type.precedence, ASSIGNMENT_PRECEDENCE)) {
@@ -5042,7 +5040,7 @@
   }
 
   Token parseUnaryExpression(Token token, bool allowCascades) {
-    String value = token.next.stringValue;
+    String? value = token.next!.stringValue;
     // Prefix:
     if (identical(value, 'await')) {
       if (inPlainSync) {
@@ -5060,39 +5058,39 @@
           // TODO(danrubel): Consider reporting "missing identifier" instead.
           codes.messageUnsupportedPrefixPlus,
           new SyntheticStringToken(
-              TokenType.IDENTIFIER, '', token.next.offset));
+              TokenType.IDENTIFIER, '', token.next!.offset));
       return parsePrimary(token, IdentifierContext.expression);
     } else if ((identical(value, '!')) ||
         (identical(value, '-')) ||
         (identical(value, '~'))) {
-      Token operator = token.next;
+      Token operator = token.next!;
       // Right associative, so we recurse at the same precedence
       // level.
       token = parsePrecedenceExpression(
-          token.next, POSTFIX_PRECEDENCE, allowCascades);
+          token.next!, POSTFIX_PRECEDENCE, allowCascades);
       listener.handleUnaryPrefixExpression(operator);
       return token;
     } else if ((identical(value, '++')) || identical(value, '--')) {
       // TODO(ahe): Validate this is used correctly.
-      Token operator = token.next;
+      Token operator = token.next!;
       // Right associative, so we recurse at the same precedence
       // level.
       token = parsePrecedenceExpression(
-          token.next, POSTFIX_PRECEDENCE, allowCascades);
+          token.next!, POSTFIX_PRECEDENCE, allowCascades);
       listener.handleUnaryPrefixAssignmentExpression(operator);
       return token;
-    } else if (token.next.isIdentifier) {
-      Token identifier = token.next;
-      if (optional(".", identifier.next)) {
-        identifier = identifier.next.next;
+    } else if (token.next!.isIdentifier) {
+      Token identifier = token.next!;
+      if (optional(".", identifier.next!)) {
+        identifier = identifier.next!.next!;
       }
       if (identifier.isIdentifier) {
         // Looking at `identifier ('.' identifier)?`.
-        if (optional("<", identifier.next)) {
+        if (optional("<", identifier.next!)) {
           TypeParamOrArgInfo typeArg = computeTypeParamOrArg(identifier);
           if (typeArg != noTypeParamOrArg) {
             Token endTypeArguments = typeArg.skip(identifier);
-            if (optional(".", endTypeArguments.next)) {
+            if (optional(".", endTypeArguments.next!)) {
               return parseImplicitCreationExpression(token, typeArg);
             }
           }
@@ -5104,11 +5102,11 @@
 
   Token parseArgumentOrIndexStar(
       Token token, TypeParamOrArgInfo typeArg, bool checkedNullAware) {
-    Token next = token.next;
+    Token next = token.next!;
     final Token beginToken = next;
     while (true) {
       bool potentialNullAware =
-          (optional('?', next) && optional('[', next.next));
+          (optional('?', next) && optional('[', next.next!));
       if (potentialNullAware && !checkedNullAware) {
         // While it's a potential null aware index it hasn't been checked.
         // It might be a conditional expression.
@@ -5120,24 +5118,24 @@
       if (optional('[', next) || potentialNullAware) {
         assert(typeArg == noTypeParamOrArg);
         Token openSquareBracket = next;
-        Token question;
+        Token? question;
         if (optional('?', next)) {
           question = next;
-          next = next.next;
+          next = next.next!;
           openSquareBracket = next;
           assert(optional('[', openSquareBracket));
         }
         bool old = mayParseFunctionExpressions;
         mayParseFunctionExpressions = true;
         token = parseExpression(next);
-        next = token.next;
+        next = token.next!;
         mayParseFunctionExpressions = old;
         if (!optional(']', next)) {
           // Recovery
           reportRecoverableError(
               next, codes.templateExpectedButGot.withArguments(']'));
           // Scanner ensures a closing ']'
-          Token endGroup = openSquareBracket.endGroup;
+          Token endGroup = openSquareBracket.endGroup!;
           if (endGroup.isSynthetic) {
             // Scanner inserted closing ']' in the wrong place, so move it.
             next = rewriter.moveSynthetic(token, endGroup);
@@ -5149,8 +5147,8 @@
         listener.handleIndexedExpression(question, openSquareBracket, next);
         token = next;
         Token bangToken = token;
-        if (optional('!', token.next)) {
-          bangToken = token.next;
+        if (optional('!', token.next!)) {
+          bangToken = token.next!;
         }
         typeArg = computeMethodTypeArguments(bangToken);
         if (typeArg != noTypeParamOrArg) {
@@ -5159,9 +5157,9 @@
             listener.handleNonNullAssertExpression(bangToken);
           }
           token = typeArg.parseArguments(bangToken, this);
-          assert(optional('(', token.next));
+          assert(optional('(', token.next!));
         }
-        next = token.next;
+        next = token.next!;
       } else if (optional('(', next)) {
         if (typeArg == noTypeParamOrArg) {
           listener.handleNoTypeArguments(next);
@@ -5169,8 +5167,8 @@
         token = parseArguments(token);
         listener.handleSend(beginToken, token);
         Token bangToken = token;
-        if (optional('!', token.next)) {
-          bangToken = token.next;
+        if (optional('!', token.next!)) {
+          bangToken = token.next!;
         }
         typeArg = computeMethodTypeArguments(bangToken);
         if (typeArg != noTypeParamOrArg) {
@@ -5179,9 +5177,9 @@
             listener.handleNonNullAssertExpression(bangToken);
           }
           token = typeArg.parseArguments(bangToken, this);
-          assert(optional('(', token.next));
+          assert(optional('(', token.next!));
         }
-        next = token.next;
+        next = token.next!;
       } else {
         break;
       }
@@ -5190,7 +5188,7 @@
   }
 
   Token parsePrimary(Token token, IdentifierContext context) {
-    final int kind = token.next.kind;
+    final int kind = token.next!.kind;
     if (kind == IDENTIFIER_TOKEN) {
       return parseSendOrFunctionLiteral(token, context);
     } else if (kind == INT_TOKEN || kind == HEXADECIMAL_TOKEN) {
@@ -5202,7 +5200,7 @@
     } else if (kind == HASH_TOKEN) {
       return parseLiteralSymbol(token);
     } else if (kind == KEYWORD_TOKEN) {
-      final String value = token.next.stringValue;
+      final String? value = token.next!.stringValue;
       if (identical(value, "true") || identical(value, "false")) {
         return parseLiteralBool(token);
       } else if (identical(value, "null")) {
@@ -5222,11 +5220,11 @@
         // Fall through to the recovery code.
       } else if (identical(value, "assert")) {
         return parseAssert(token, Assert.Expression);
-      } else if (token.next.isIdentifier) {
+      } else if (token.next!.isIdentifier) {
         return parseSendOrFunctionLiteral(token, context);
       } else if (identical(value, "return")) {
         // Recovery
-        token = token.next;
+        token = token.next!;
         reportRecoverableErrorWithToken(token, codes.templateUnexpectedToken);
         return parsePrimary(token, context);
       } else {
@@ -5235,11 +5233,11 @@
     } else if (kind == OPEN_PAREN_TOKEN) {
       return parseParenthesizedExpressionOrFunctionLiteral(token);
     } else if (kind == OPEN_SQUARE_BRACKET_TOKEN ||
-        optional('[]', token.next)) {
-      listener.handleNoTypeArguments(token.next);
+        optional('[]', token.next!)) {
+      listener.handleNoTypeArguments(token.next!);
       return parseLiteralListSuffix(token, /* constKeyword = */ null);
     } else if (kind == OPEN_CURLY_BRACKET_TOKEN) {
-      listener.handleNoTypeArguments(token.next);
+      listener.handleNoTypeArguments(token.next!);
       return parseLiteralSetOrMapSuffix(token, /* constKeyword = */ null);
     } else if (kind == LT_TOKEN) {
       return parseLiteralListSetMapOrFunction(token, /* constKeyword = */ null);
@@ -5253,9 +5251,9 @@
   }
 
   Token parseParenthesizedExpressionOrFunctionLiteral(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     assert(optional('(', next));
-    Token nextToken = next.endGroup.next;
+    Token nextToken = next.endGroup!.next!;
     int kind = nextToken.kind;
     if (mayParseFunctionExpressions) {
       if ((identical(kind, FUNCTION_TOKEN) ||
@@ -5272,7 +5270,7 @@
         // If there is a stray simple identifier in the function expression
         // because the user is typing (e.g. `() asy {}`) then continue parsing
         // and allow parseFunctionExpression to report an unexpected token.
-        kind = nextToken.next.kind;
+        kind = nextToken.next!.kind;
         if ((identical(kind, FUNCTION_TOKEN) ||
             identical(kind, OPEN_CURLY_BRACKET_TOKEN))) {
           listener.handleNoTypeVariables(next);
@@ -5288,7 +5286,7 @@
   }
 
   Token ensureParenthesizedCondition(Token token) {
-    Token openParen = token.next;
+    Token openParen = token.next!;
     if (!optional('(', openParen)) {
       // Recover
       reportRecoverableError(
@@ -5301,19 +5299,19 @@
   }
 
   Token parseParenthesizedExpression(Token token) {
-    Token begin = token.next;
+    Token begin = token.next!;
     token = parseExpressionInParenthesis(token);
     listener.handleParenthesizedExpression(begin);
     return token;
   }
 
   Token parseExpressionInParenthesis(Token token) {
-    return parseExpressionInParenthesisRest(token.next);
+    return parseExpressionInParenthesisRest(token.next!);
   }
 
   Token parseExpressionInParenthesisRest(Token token) {
     assert(optional('(', token));
-    BeginToken begin = token;
+    BeginToken begin = token as BeginToken;
     token = parseExpression(token);
     token = ensureCloseParen(token, begin);
     assert(optional(')', token));
@@ -5321,29 +5319,29 @@
   }
 
   Token parseThisExpression(Token token, IdentifierContext context) {
-    Token thisToken = token = token.next;
+    Token thisToken = token = token.next!;
     assert(optional('this', thisToken));
     listener.handleThisExpression(thisToken, context);
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('(', next)) {
       // Constructor forwarding.
       listener.handleNoTypeArguments(next);
       token = parseArguments(token);
-      listener.handleSend(thisToken, token.next);
+      listener.handleSend(thisToken, token.next!);
     }
     return token;
   }
 
   Token parseSuperExpression(Token token, IdentifierContext context) {
-    Token superToken = token = token.next;
+    Token superToken = token = token.next!;
     assert(optional('super', token));
     listener.handleSuperExpression(superToken, context);
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('(', next)) {
       // Super constructor.
       listener.handleNoTypeArguments(next);
       token = parseArguments(token);
-      listener.handleSend(superToken, token.next);
+      listener.handleSend(superToken, token.next!);
     } else if (optional("?.", next)) {
       reportRecoverableError(next, codes.messageSuperNullAware);
     }
@@ -5362,30 +5360,30 @@
   /// Provide a [constKeyword] if the literal is preceded by 'const', or `null`
   /// if not. This is a suffix parser because it is assumed that type arguments
   /// have been parsed, or `listener.handleNoTypeArguments` has been executed.
-  Token parseLiteralListSuffix(Token token, Token constKeyword) {
+  Token parseLiteralListSuffix(Token token, Token? constKeyword) {
     Token beforeToken = token;
-    Token beginToken = token = token.next;
+    Token beginToken = token = token.next!;
     assert(optional('[', token) || optional('[]', token));
     int count = 0;
     if (optional('[]', token)) {
-      token = rewriteSquareBrackets(beforeToken).next;
+      token = rewriteSquareBrackets(beforeToken).next!;
       listener.handleLiteralList(
           /* count = */ 0,
           token,
           constKeyword,
-          token.next);
-      return token.next;
+          token.next!);
+      return token.next!;
     }
     bool old = mayParseFunctionExpressions;
     mayParseFunctionExpressions = true;
     while (true) {
-      Token next = token.next;
+      Token next = token.next!;
       if (optional(']', next)) {
         token = next;
         break;
       }
       int ifCount = 0;
-      LiteralEntryInfo info = computeLiteralEntry(token);
+      LiteralEntryInfo? info = computeLiteralEntry(token);
       while (info != null) {
         if (info.hasEntry) {
           token = parseExpression(token);
@@ -5395,7 +5393,7 @@
         ifCount += info.ifConditionDelta;
         info = info.computeNext(token);
       }
-      next = token.next;
+      next = token.next!;
       ++count;
       if (!optional(',', next)) {
         if (optional(']', next)) {
@@ -5405,15 +5403,15 @@
 
         // Recovery
         if (!looksLikeLiteralEntry(next)) {
-          if (beginToken.endGroup.isSynthetic) {
+          if (beginToken.endGroup!.isSynthetic) {
             // The scanner has already reported an error,
             // but inserted `]` in the wrong place.
-            token = rewriter.moveSynthetic(token, beginToken.endGroup);
+            token = rewriter.moveSynthetic(token, beginToken.endGroup!);
           } else {
             // Report an error and jump to the end of the list.
             reportRecoverableError(
                 next, codes.templateExpectedButGot.withArguments(']'));
-            token = beginToken.endGroup;
+            token = beginToken.endGroup!;
           }
           break;
         }
@@ -5434,10 +5432,10 @@
 
   /// This method parses the portion of a set or map literal that starts with
   /// the left curly brace when there are no leading type arguments.
-  Token parseLiteralSetOrMapSuffix(Token token, Token constKeyword) {
-    Token leftBrace = token = token.next;
+  Token parseLiteralSetOrMapSuffix(Token token, Token? constKeyword) {
+    Token leftBrace = token = token.next!;
     assert(optional('{', leftBrace));
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('}', next)) {
       listener.handleLiteralSetOrMap(/* count = */ 0, leftBrace, constKeyword,
           next, /* hasSetEntry = */ false);
@@ -5449,30 +5447,30 @@
     int count = 0;
     // TODO(danrubel): hasSetEntry parameter exists for replicating existing
     // behavior and will be removed once unified collection has been enabled
-    bool hasSetEntry;
+    bool? hasSetEntry;
 
     while (true) {
       int ifCount = 0;
-      LiteralEntryInfo info = computeLiteralEntry(token);
+      LiteralEntryInfo? info = computeLiteralEntry(token);
       if (info == simpleEntry) {
         // TODO(danrubel): Remove this section and use the while loop below
         // once hasSetEntry is no longer needed.
         token = parseExpression(token);
-        bool isMapEntry = optional(':', token.next);
+        bool isMapEntry = optional(':', token.next!);
         hasSetEntry ??= !isMapEntry;
         if (isMapEntry) {
-          Token colon = token.next;
+          Token colon = token.next!;
           token = parseExpression(colon);
-          listener.handleLiteralMapEntry(colon, token.next);
+          listener.handleLiteralMapEntry(colon, token.next!);
         }
       } else {
         while (info != null) {
           if (info.hasEntry) {
             token = parseExpression(token);
-            if (optional(':', token.next)) {
-              Token colon = token.next;
+            if (optional(':', token.next!)) {
+              Token colon = token.next!;
               token = parseExpression(colon);
-              listener.handleLiteralMapEntry(colon, token.next);
+              listener.handleLiteralMapEntry(colon, token.next!);
             }
           } else {
             token = info.parse(token, this);
@@ -5482,12 +5480,12 @@
         }
       }
       ++count;
-      next = token.next;
+      next = token.next!;
 
-      Token comma;
+      Token? comma;
       if (optional(',', next)) {
         comma = token = next;
-        next = token.next;
+        next = token.next!;
       }
       if (optional('}', next)) {
         listener.handleLiteralSetOrMap(
@@ -5512,7 +5510,7 @@
           reportRecoverableError(
               next, codes.templateExpectedButGot.withArguments('}'));
           // Scanner guarantees a closing curly bracket
-          next = leftBrace.endGroup;
+          next = leftBrace.endGroup!;
           listener.handleLiteralSetOrMap(
               count, leftBrace, constKeyword, next, hasSetEntry ?? false);
           mayParseFunctionExpressions = old;
@@ -5527,9 +5525,9 @@
   /// This is a suffix parser because it is assumed that type arguments have
   /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
   Token parseLiteralFunctionSuffix(Token token) {
-    assert(optional('(', token.next));
+    assert(optional('(', token.next!));
     // Scanner ensures `(` has matching `)`.
-    Token next = token.next.endGroup.next;
+    Token next = token.next!.endGroup!.next!;
     int kind = next.kind;
     if (!identical(kind, FUNCTION_TOKEN) &&
         !identical(kind, OPEN_CURLY_BRACKET_TOKEN) &&
@@ -5550,12 +5548,12 @@
   ///       typeParameters formalParameterList functionBody
   /// Provide token for [constKeyword] if preceded by 'const', null if not.
   Token parseLiteralListSetMapOrFunction(
-      final Token start, Token constKeyword) {
-    assert(optional('<', start.next));
+      final Token start, Token? constKeyword) {
+    assert(optional('<', start.next!));
     TypeParamOrArgInfo typeParamOrArg =
         computeTypeParamOrArg(start, /* inDeclaration = */ true);
     Token token = typeParamOrArg.skip(start);
-    if (optional('(', token.next)) {
+    if (optional('(', token.next!)) {
       if (constKeyword != null) {
         reportRecoverableErrorWithToken(
             constKeyword, codes.templateUnexpectedToken);
@@ -5565,10 +5563,10 @@
     }
     // Note that parseArguments can rewrite the token stream!
     token = typeParamOrArg.parseArguments(start, this);
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('{', next)) {
       if (typeParamOrArg.typeArgumentCount > 2) {
-        reportRecoverableErrorWithEnd(start.next, token,
+        reportRecoverableErrorWithEnd(start.next!, token,
             codes.messageSetOrMapLiteralTooManyTypeArguments);
       }
       return parseLiteralSetOrMapSuffix(token, constKeyword);
@@ -5594,14 +5592,14 @@
     // Assume the listener rejects non-string keys.
     // TODO(brianwilkerson): Change the assumption above by moving error
     // checking into the parser, making it possible to recover.
-    LiteralEntryInfo info = computeLiteralEntry(token);
+    LiteralEntryInfo? info = computeLiteralEntry(token);
     while (info != null) {
       if (info.hasEntry) {
         token = parseExpression(token);
         Token colon = ensureColon(token);
         token = parseExpression(colon);
         // TODO remove unused 2nd parameter
-        listener.handleLiteralMapEntry(colon, token.next);
+        listener.handleLiteralMapEntry(colon, token.next!);
       } else {
         token = info.parse(token, this);
       }
@@ -5616,12 +5614,12 @@
     }
     TypeInfo typeInfo = computeType(token, /* required = */ false);
     Token beforeName = typeInfo.skipType(token);
-    Token name = beforeName.next;
+    Token name = beforeName.next!;
     if (name.isIdentifier) {
       TypeParamOrArgInfo typeParam = computeTypeParamOrArg(name);
-      Token next = typeParam.skip(name).next;
+      Token next = typeParam.skip(name).next!;
       if (optional('(', next)) {
-        if (looksLikeFunctionBody(next.endGroup.next)) {
+        if (looksLikeFunctionBody(next.endGroup!.next!)) {
           return parseFunctionLiteral(
               token, beforeName, name, typeInfo, typeParam, context);
         }
@@ -5631,7 +5629,7 @@
   }
 
   Token ensureArguments(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     if (!optional('(', next)) {
       reportRecoverableError(
           token, codes.templateExpectedAfterButGot.withArguments('('));
@@ -5641,7 +5639,7 @@
   }
 
   Token parseConstructorInvocationArguments(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     if (!optional('(', next)) {
       // Recovery: Check for invalid type parameters
       TypeParamOrArgInfo typeArg = computeTypeParamOrArg(token);
@@ -5653,7 +5651,7 @@
             token, codes.messageConstructorWithTypeArguments);
         token = typeArg.parseArguments(token, this);
         listener.handleInvalidTypeArguments(token);
-        next = token.next;
+        next = token.next!;
       }
       if (!optional('(', next)) {
         next = rewriter.insertParens(token, /* includeIdentifier = */ false);
@@ -5668,7 +5666,7 @@
   /// ;
   /// ```
   Token parseNewExpression(Token token) {
-    Token newKeyword = token.next;
+    Token newKeyword = token.next!;
     assert(optional('new', newKeyword));
     listener.beginNewExpression(newKeyword);
     token = parseConstructorReference(newKeyword);
@@ -5705,28 +5703,28 @@
   /// ;
   /// ```
   Token parseConstExpression(Token token) {
-    Token constKeyword = token = token.next;
+    Token constKeyword = token = token.next!;
     assert(optional('const', constKeyword));
-    Token next = token.next;
-    final String value = next.stringValue;
+    Token next = token.next!;
+    final String? value = next.stringValue;
     if ((identical(value, '[')) || (identical(value, '[]'))) {
       listener.beginConstLiteral(next);
       listener.handleNoTypeArguments(next);
       token = parseLiteralListSuffix(token, constKeyword);
-      listener.endConstLiteral(token.next);
+      listener.endConstLiteral(token.next!);
       return token;
     }
     if (identical(value, '{')) {
       listener.beginConstLiteral(next);
       listener.handleNoTypeArguments(next);
       token = parseLiteralSetOrMapSuffix(token, constKeyword);
-      listener.endConstLiteral(token.next);
+      listener.endConstLiteral(token.next!);
       return token;
     }
     if (identical(value, '<')) {
       listener.beginConstLiteral(next);
       token = parseLiteralListSetMapOrFunction(token, constKeyword);
-      listener.endConstLiteral(token.next);
+      listener.endConstLiteral(token.next!);
       return token;
     }
     listener.beginConstExpression(constKeyword);
@@ -5742,7 +5740,7 @@
   /// ;
   /// ```
   Token parseLiteralInt(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(identical(token.kind, INT_TOKEN) ||
         identical(token.kind, HEXADECIMAL_TOKEN));
     listener.handleLiteralInt(token);
@@ -5755,7 +5753,7 @@
   /// ;
   /// ```
   Token parseLiteralDouble(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(identical(token.kind, DOUBLE_TOKEN));
     listener.handleLiteralDouble(token);
     return token;
@@ -5768,12 +5766,12 @@
   /// ```
   Token parseLiteralString(Token token) {
     Token startToken = token;
-    assert(identical(token.next.kind, STRING_TOKEN));
+    assert(identical(token.next!.kind, STRING_TOKEN));
     bool old = mayParseFunctionExpressions;
     mayParseFunctionExpressions = true;
     token = parseSingleLiteralString(token);
     int count = 1;
-    while (identical(token.next.kind, STRING_TOKEN)) {
+    while (identical(token.next!.kind, STRING_TOKEN)) {
       token = parseSingleLiteralString(token);
       count++;
     }
@@ -5790,10 +5788,10 @@
   /// ;
   /// ```
   Token parseLiteralSymbol(Token token) {
-    Token hashToken = token = token.next;
+    Token hashToken = token = token.next!;
     assert(optional('#', hashToken));
     listener.beginLiteralSymbol(hashToken);
-    Token next = token.next;
+    Token next = token.next!;
     if (next.isUserDefinableOperator) {
       listener.handleOperator(next);
       listener.endLiteralSymbol(hashToken, /* identifierCount = */ 1);
@@ -5805,10 +5803,10 @@
     } else {
       int count = 1;
       token = ensureIdentifier(token, IdentifierContext.literalSymbol);
-      while (optional('.', token.next)) {
+      while (optional('.', token.next!)) {
         count++;
         token = ensureIdentifier(
-            token.next, IdentifierContext.literalSymbolContinuation);
+            token.next!, IdentifierContext.literalSymbolContinuation);
       }
       listener.endLiteralSymbol(hashToken, count);
       return token;
@@ -5816,21 +5814,21 @@
   }
 
   Token parseSingleLiteralString(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(identical(token.kind, STRING_TOKEN));
     listener.beginLiteralString(token);
     // Parsing the prefix, for instance 'x of 'x${id}y${id}z'
     int interpolationCount = 0;
-    Token next = token.next;
+    Token next = token.next!;
     int kind = next.kind;
     while (kind != EOF_TOKEN) {
       if (identical(kind, STRING_INTERPOLATION_TOKEN)) {
         // Parsing ${expression}.
-        token = parseExpression(next).next;
+        token = parseExpression(next).next!;
         if (!optional('}', token)) {
           reportRecoverableError(
               token, codes.templateExpectedButGot.withArguments('}'));
-          token = next.endGroup;
+          token = next.endGroup!;
         }
         listener.handleInterpolationExpression(next, token);
       } else if (identical(kind, STRING_INTERPOLATION_IDENTIFIER_TOKEN)) {
@@ -5843,7 +5841,7 @@
       ++interpolationCount;
       // Parsing the infix/suffix, for instance y and z' of 'x${id}y${id}z'
       token = parseStringPart(token);
-      next = token.next;
+      next = token.next!;
       kind = next.kind;
     }
     listener.endLiteralString(interpolationCount, next);
@@ -5851,7 +5849,7 @@
   }
 
   Token parseIdentifierExpression(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     if (next.kind == KEYWORD_TOKEN && identical(next.stringValue, "this")) {
       listener.handleThisExpression(next, IdentifierContext.expression);
       return next;
@@ -5867,7 +5865,7 @@
   /// ;
   /// ```
   Token parseLiteralBool(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional('false', token) || optional('true', token));
     listener.handleLiteralBool(token);
     return token;
@@ -5879,7 +5877,7 @@
   /// ;
   /// ```
   Token parseLiteralNull(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional('null', token));
     listener.handleLiteralNull(token);
     return token;
@@ -5898,25 +5896,25 @@
     if (typeArg != noTypeParamOrArg) {
       token = typeArg.parseArguments(token, this);
     } else {
-      listener.handleNoTypeArguments(token.next);
+      listener.handleNoTypeArguments(token.next!);
     }
     token = parseArgumentsOpt(token);
-    listener.handleSend(beginToken, token.next);
+    listener.handleSend(beginToken, token.next!);
     return token;
   }
 
   Token skipArgumentsOpt(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     listener.handleNoArguments(next);
     if (optional('(', next)) {
-      return next.endGroup;
+      return next.endGroup!;
     } else {
       return token;
     }
   }
 
   Token parseArgumentsOpt(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     if (!optional('(', next)) {
       listener.handleNoArguments(next);
       return token;
@@ -5940,7 +5938,7 @@
   /// ;
   /// ```
   Token parseArguments(Token token) {
-    return parseArgumentsRest(token.next);
+    return parseArgumentsRest(token.next!);
   }
 
   Token parseArgumentsRest(Token token) {
@@ -5952,16 +5950,16 @@
     bool old = mayParseFunctionExpressions;
     mayParseFunctionExpressions = true;
     while (true) {
-      Token next = token.next;
+      Token next = token.next!;
       if (optional(')', next)) {
         token = next;
         break;
       }
-      Token colon = null;
-      if (optional(':', next.next)) {
+      Token? colon = null;
+      if (optional(':', next.next!)) {
         token =
             ensureIdentifier(token, IdentifierContext.namedArgumentReference)
-                .next;
+                .next!;
         colon = token;
         hasSeenNamedArgument = true;
       } else if (hasSeenNamedArgument) {
@@ -5969,7 +5967,7 @@
         reportRecoverableError(next, codes.messagePositionalAfterNamedArgument);
       }
       token = parseExpression(token);
-      next = token.next;
+      next = token.next!;
       if (colon != null) listener.handleNamedArgument(colon);
       ++argumentCount;
       if (!optional(',', next)) {
@@ -6004,11 +6002,11 @@
   /// ;
   /// ```
   Token parseIsOperatorRest(Token token) {
-    Token operator = token = token.next;
+    Token operator = token = token.next!;
     assert(optional('is', operator));
-    Token not = null;
-    if (optional('!', token.next)) {
-      not = token = token.next;
+    Token? not = null;
+    if (optional('!', token.next!)) {
+      not = token = token.next!;
     }
     listener.beginIsOperatorType(operator);
     TypeInfo typeInfo = computeTypeAfterIsOrAs(token);
@@ -6021,7 +6019,7 @@
   TypeInfo computeTypeAfterIsOrAs(Token token) {
     TypeInfo typeInfo = computeType(token, /* required = */ true);
     if (typeInfo.isNullable) {
-      Token next = typeInfo.skipType(token).next;
+      Token next = typeInfo.skipType(token).next!;
       if (!isOneOfOrEof(
           next, const [')', '?', '??', ',', ';', ':', 'is', 'as', '..'])) {
         // TODO(danrubel): investigate other situations
@@ -6039,7 +6037,7 @@
   /// ;
   /// ```
   Token parseAsOperatorRest(Token token) {
-    Token operator = token = token.next;
+    Token operator = token = token.next!;
     assert(optional('as', operator));
     listener.beginAsOperatorType(operator);
     TypeInfo typeInfo = computeTypeAfterIsOrAs(token);
@@ -6051,20 +6049,20 @@
 
   Token skipChainedAsIsOperators(Token token) {
     while (true) {
-      Token next = token.next;
-      String value = next.stringValue;
+      Token next = token.next!;
+      String? value = next.stringValue;
       if (!identical(value, 'is') && !identical(value, 'as')) {
         return token;
       }
       // The is- and as-operators cannot be chained.
       // TODO(danrubel): Consider a better error message.
       reportRecoverableErrorWithToken(next, codes.templateUnexpectedToken);
-      if (optional('!', next.next)) {
-        next = next.next;
+      if (optional('!', next.next!)) {
+        next = next.next!;
       }
       TypeInfo typeInfo = computeTypeAfterIsOrAs(next);
       token = typeInfo.skipType(next);
-      next = token.next;
+      next = token.next!;
       value = next.stringValue;
     }
   }
@@ -6073,16 +6071,16 @@
   /// without a return type.
   bool looksLikeLocalFunction(Token token) {
     if (token.isIdentifier) {
-      if (optional('<', token.next)) {
+      if (optional('<', token.next!)) {
         TypeParamOrArgInfo typeParam = computeTypeParamOrArg(token);
         if (typeParam == noTypeParamOrArg) {
           return false;
         }
         token = typeParam.skip(token);
       }
-      token = token.next;
+      token = token.next!;
       if (optional('(', token)) {
-        token = token.endGroup.next;
+        token = token.endGroup!.next!;
         return optional('{', token) ||
             optional('=>', token) ||
             optional('async', token) ||
@@ -6104,16 +6102,16 @@
   }
 
   Token parseExpressionStatementOrConstDeclaration(final Token start) {
-    Token constToken = start.next;
+    Token constToken = start.next!;
     assert(optional('const', constToken));
-    if (!isModifier(constToken.next)) {
+    if (!isModifier(constToken.next!)) {
       TypeInfo typeInfo = computeType(constToken, /* required = */ false);
       if (typeInfo == noType) {
-        Token next = constToken.next;
+        Token next = constToken.next!;
         if (!next.isIdentifier) {
           return parseExpressionStatement(start);
         }
-        next = next.next;
+        next = next.next!;
         if (!(optional('=', next) ||
             // Recovery
             next.isKeywordOrIdentifier ||
@@ -6149,28 +6147,28 @@
   Token parseExpressionStatementOrDeclaration(final Token start,
       [bool onlyParseVariableDeclarationStart = false]) {
     Token token = start;
-    Token next = token.next;
+    Token next = token.next!;
     if (optional('@', next)) {
       token = parseMetadataStar(token);
-      next = token.next;
+      next = token.next!;
     }
 
-    Token lateToken;
-    Token varFinalOrConst;
+    Token? lateToken;
+    Token? varFinalOrConst;
 
     if (isModifier(next)) {
       if (optional('var', next) ||
           optional('final', next) ||
           optional('const', next)) {
-        varFinalOrConst = token = token.next;
-        next = token.next;
+        varFinalOrConst = token = token.next!;
+        next = token.next!;
       } else if (optional('late', next)) {
         lateToken = token = next;
-        next = token.next;
+        next = token.next!;
         if (isModifier(next) &&
             (optional('var', next) || optional('final', next))) {
           varFinalOrConst = token = next;
-          next = token.next;
+          next = token.next!;
         }
       }
 
@@ -6181,12 +6179,10 @@
           ..varFinalOrConst = varFinalOrConst;
 
         token = context.parseVariableDeclarationModifiers(token);
-        next = token.next;
+        next = token.next!;
 
         lateToken = context.lateToken;
         varFinalOrConst = context.varFinalOrConst;
-
-        context = null;
       }
     }
 
@@ -6203,32 +6199,31 @@
   Token parseExpressionStatementOrDeclarationAfterModifiers(
       Token beforeType,
       Token start,
-      Token lateToken,
-      Token varFinalOrConst,
-      TypeInfo typeInfo,
+      Token? lateToken,
+      Token? varFinalOrConst,
+      TypeInfo? typeInfo,
       bool onlyParseVariableDeclarationStart) {
     // In simple cases check for bad 'late' modifier in non-nnbd-mode.
     if (typeInfo == null &&
         lateToken == null &&
         varFinalOrConst == null &&
         beforeType == start &&
-        _isUseOfLateInNonNNBD(beforeType.next)) {
-      lateToken = beforeType.next;
+        _isUseOfLateInNonNNBD(beforeType.next!)) {
+      lateToken = beforeType.next!;
       reportRecoverableErrorWithToken(
           lateToken, codes.templateUnexpectedModifierInNonNnbd);
-      beforeType = start = beforeType.next;
+      beforeType = start = beforeType.next!;
 
       // The below doesn't parse modifiers, so we need to do it here.
       ModifierRecoveryContext context = new ModifierRecoveryContext(this);
       beforeType =
           start = context.parseVariableDeclarationModifiers(beforeType);
       varFinalOrConst = context.varFinalOrConst;
-      context = null;
     }
     typeInfo ??= computeType(beforeType, /* required = */ false);
 
     Token token = typeInfo.skipType(beforeType);
-    Token next = token.next;
+    Token next = token.next!;
 
     if (onlyParseVariableDeclarationStart) {
       if (lateToken != null) {
@@ -6245,17 +6240,17 @@
           reportRecoverableErrorWithToken(
               lateToken, codes.templateExtraneousModifier);
         }
-        if (!optional('@', start.next)) {
-          listener.beginMetadataStar(start.next);
+        if (!optional('@', start.next!)) {
+          listener.beginMetadataStar(start.next!);
           listener.endMetadataStar(/* count = */ 0);
         }
         Token beforeFormals =
             computeTypeParamOrArg(next).parseVariables(next, this);
-        listener.beginLocalFunctionDeclaration(start.next);
+        listener.beginLocalFunctionDeclaration(start.next!);
         token = typeInfo.parseType(beforeType, this);
         return parseNamedFunctionRest(
             token,
-            start.next,
+            start.next!,
             beforeFormals,
             /* isFunctionExpression = */ false);
       }
@@ -6271,7 +6266,7 @@
             next, codes.templateExpectedIdentifier.withArguments(next));
         next = rewriter.insertSyntheticIdentifier(next);
       }
-      Token afterIdentifier = next.next;
+      Token afterIdentifier = next.next!;
       //
       // found <typeref> `?` <identifier>
       // with no annotations or modifiers preceeding it
@@ -6285,7 +6280,7 @@
         listener = new ForwardingListener();
         // TODO(danrubel): consider using TokenStreamGhostWriter here
         Token afterExpression =
-            parseExpressionWithoutCascade(afterIdentifier).next;
+            parseExpressionWithoutCascade(afterIdentifier).next!;
         listener = originalListener;
 
         if (optional(':', afterExpression)) {
@@ -6293,7 +6288,7 @@
           // Drop the type information and reset the last consumed token.
           typeInfo = noType;
           token = start;
-          next = token.next;
+          next = token.next!;
         }
       } else if (!afterIdentifier.isKeyword &&
           !isOneOfOrEof(afterIdentifier, const [';', ',', ')'])) {
@@ -6301,7 +6296,7 @@
         // Drop the type information and reset the last consumed token.
         typeInfo = noType;
         token = start;
-        next = token.next;
+        next = token.next!;
       }
     }
 
@@ -6321,12 +6316,12 @@
       // Detect expressions such as identifier `as` identifier
       // and treat those as expressions.
       if (optional('as', next) || optional('is', next)) {
-        int kind = next.next.kind;
+        int kind = next.next!.kind;
         if (EQ_TOKEN != kind &&
             SEMICOLON_TOKEN != kind &&
             COMMA_TOKEN != kind) {
           if (onlyParseVariableDeclarationStart) {
-            if (!optional('in', next.next)) {
+            if (!optional('in', next.next!)) {
               return start;
             }
           } else {
@@ -6351,12 +6346,12 @@
       }
     }
 
-    if (!optional('@', start.next)) {
-      listener.beginMetadataStar(start.next);
+    if (!optional('@', start.next!)) {
+      listener.beginMetadataStar(start.next!);
       listener.endMetadataStar(/* count = */ 0);
     }
     token = typeInfo.parseType(beforeType, this);
-    next = token.next;
+    next = token.next!;
     listener.beginVariablesDeclaration(next, lateToken, varFinalOrConst);
     if (!onlyParseVariableDeclarationStart) {
       token =
@@ -6368,8 +6363,8 @@
   Token parseVariablesDeclarationRest(Token token, bool endWithSemicolon) {
     int count = 1;
     token = parseOptionallyInitializedIdentifier(token);
-    while (optional(',', token.next)) {
-      token = parseOptionallyInitializedIdentifier(token.next);
+    while (optional(',', token.next!)) {
+      token = parseOptionallyInitializedIdentifier(token.next!);
       ++count;
     }
     if (endWithSemicolon) {
@@ -6397,16 +6392,16 @@
   /// ;
   /// ```
   Token parseIfStatement(Token token) {
-    Token ifToken = token.next;
+    Token ifToken = token.next!;
     assert(optional('if', ifToken));
     listener.beginIfStatement(ifToken);
     token = ensureParenthesizedCondition(ifToken);
-    listener.beginThenStatement(token.next);
+    listener.beginThenStatement(token.next!);
     token = parseStatement(token);
     listener.endThenStatement(token);
-    Token elseToken = null;
-    if (optional('else', token.next)) {
-      elseToken = token.next;
+    Token? elseToken = null;
+    if (optional('else', token.next!)) {
+      elseToken = token.next!;
       listener.beginElseStatement(elseToken);
       token = parseStatement(elseToken);
       listener.endElseStatement(elseToken);
@@ -6432,16 +6427,16 @@
   ///   expression? ';'
   /// ;
   /// ```
-  Token parseForStatement(Token token, Token awaitToken) {
-    Token forToken = token = token.next;
+  Token parseForStatement(Token token, Token? awaitToken) {
+    Token forToken = token = token.next!;
     assert(awaitToken == null || optional('await', awaitToken));
     assert(optional('for', token));
     listener.beginForStatement(forToken);
 
     token = parseForLoopPartsStart(awaitToken, forToken);
-    Token identifier = token.next;
+    Token identifier = token.next!;
     token = parseForLoopPartsMid(token, awaitToken, forToken);
-    if (optional('in', token.next) || optional(':', token.next)) {
+    if (optional('in', token.next!) || optional(':', token.next!)) {
       // Process `for ( ... in ... )`
       return parseForInRest(token, awaitToken, forToken, identifier);
     } else {
@@ -6452,8 +6447,8 @@
 
   /// Parse the start of a for loop control structure
   /// from the open parenthesis up to but not including the identifier.
-  Token parseForLoopPartsStart(Token awaitToken, Token forToken) {
-    Token leftParenthesis = forToken.next;
+  Token parseForLoopPartsStart(Token? awaitToken, Token forToken) {
+    Token leftParenthesis = forToken.next!;
     if (!optional('(', leftParenthesis)) {
       // Recovery
       reportRecoverableError(
@@ -6462,7 +6457,7 @@
       BeginToken openParen = rewriter.insertToken(
           forToken,
           new SyntheticBeginToken(
-              TokenType.OPEN_PAREN, leftParenthesis.offset));
+              TokenType.OPEN_PAREN, leftParenthesis.offset)) as BeginToken;
 
       Token token;
       if (awaitToken != null) {
@@ -6493,25 +6488,25 @@
 
   /// Parse the remainder of the local variable declaration
   /// or an expression if no local variable declaration was found.
-  Token parseForLoopPartsMid(Token token, Token awaitToken, Token forToken) {
+  Token parseForLoopPartsMid(Token token, Token? awaitToken, Token forToken) {
     if (token != forToken.next) {
       token =
           parseVariablesDeclarationRest(token, /* endWithSemicolon = */ false);
       listener.handleForInitializerLocalVariableDeclaration(
-          token, optional('in', token.next) || optional(':', token.next));
-    } else if (optional(';', token.next)) {
-      listener.handleForInitializerEmptyStatement(token.next);
+          token, optional('in', token.next!) || optional(':', token.next!));
+    } else if (optional(';', token.next!)) {
+      listener.handleForInitializerEmptyStatement(token.next!);
     } else {
       token = parseExpression(token);
       listener.handleForInitializerExpressionStatement(
           token,
-          optional('in', token.next) ||
-              optional(':', token.next) ||
+          optional('in', token.next!) ||
+              optional(':', token.next!) ||
               // If this is an empty `await for`, we rewrite it into an
               // `await for (_ in _)`.
-              (awaitToken != null && optional(')', token.next)));
+              (awaitToken != null && optional(')', token.next!)));
     }
-    Token next = token.next;
+    Token next = token.next!;
     if (optional(';', next)) {
       if (awaitToken != null) {
         reportRecoverableError(awaitToken, codes.messageInvalidAwaitFor);
@@ -6541,37 +6536,37 @@
   ///    | identifier 'in' expression
   /// ;
   /// ```
-  Token parseForRest(Token awaitToken, Token token, Token forToken) {
+  Token parseForRest(Token? awaitToken, Token token, Token forToken) {
     token = parseForLoopPartsRest(token, forToken, awaitToken);
-    listener.beginForStatementBody(token.next);
+    listener.beginForStatementBody(token.next!);
     LoopState savedLoopState = loopState;
     loopState = LoopState.InsideLoop;
     token = parseStatement(token);
     loopState = savedLoopState;
-    listener.endForStatementBody(token.next);
-    listener.endForStatement(token.next);
+    listener.endForStatementBody(token.next!);
+    listener.endForStatement(token.next!);
     return token;
   }
 
-  Token parseForLoopPartsRest(Token token, Token forToken, Token awaitToken) {
-    Token leftParenthesis = forToken.next;
+  Token parseForLoopPartsRest(Token token, Token forToken, Token? awaitToken) {
+    Token leftParenthesis = forToken.next!;
     assert(optional('for', forToken));
     assert(optional('(', leftParenthesis));
 
     Token leftSeparator = ensureSemicolon(token);
-    if (optional(';', leftSeparator.next)) {
+    if (optional(';', leftSeparator.next!)) {
       token = parseEmptyStatement(leftSeparator);
     } else {
       token = parseExpressionStatement(leftSeparator);
     }
     int expressionCount = 0;
     while (true) {
-      Token next = token.next;
+      Token next = token.next!;
       if (optional(')', next)) {
         token = next;
         break;
       }
-      token = parseExpression(token).next;
+      token = parseExpression(token).next!;
       ++expressionCount;
       if (!optional(',', token)) {
         break;
@@ -6579,7 +6574,7 @@
     }
     if (token != leftParenthesis.endGroup) {
       reportRecoverableErrorWithToken(token, codes.templateUnexpectedToken);
-      token = leftParenthesis.endGroup;
+      token = leftParenthesis.endGroup!;
     }
     listener.handleForLoopParts(
         forToken, leftParenthesis, leftSeparator, expressionCount);
@@ -6599,23 +6594,23 @@
   /// ;
   /// ```
   Token parseForInRest(
-      Token token, Token awaitToken, Token forToken, Token identifier) {
+      Token token, Token? awaitToken, Token forToken, Token identifier) {
     token = parseForInLoopPartsRest(token, awaitToken, forToken, identifier);
-    listener.beginForInBody(token.next);
+    listener.beginForInBody(token.next!);
     LoopState savedLoopState = loopState;
     loopState = LoopState.InsideLoop;
     token = parseStatement(token);
     loopState = savedLoopState;
-    listener.endForInBody(token.next);
-    listener.endForIn(token.next);
+    listener.endForInBody(token.next!);
+    listener.endForIn(token.next!);
     return token;
   }
 
   Token parseForInLoopPartsRest(
-      Token token, Token awaitToken, Token forToken, Token identifier) {
-    Token inKeyword = token.next;
+      Token token, Token? awaitToken, Token forToken, Token identifier) {
+    Token inKeyword = token.next!;
     assert(optional('for', forToken));
-    assert(optional('(', forToken.next));
+    assert(optional('(', forToken.next!));
     assert(optional('in', inKeyword) || optional(':', inKeyword));
 
     if (!identifier.isIdentifier) {
@@ -6624,24 +6619,24 @@
       reportRecoverableErrorWithToken(
           identifier, codes.templateExpectedIdentifier);
     } else if (identifier != token) {
-      if (optional('=', identifier.next)) {
+      if (optional('=', identifier.next!)) {
         reportRecoverableError(
-            identifier.next, codes.messageInitializedVariableInForEach);
+            identifier.next!, codes.messageInitializedVariableInForEach);
       } else {
         reportRecoverableErrorWithToken(
-            identifier.next, codes.templateUnexpectedToken);
+            identifier.next!, codes.templateUnexpectedToken);
       }
     } else if (awaitToken != null && !inAsync) {
       // TODO(danrubel): consider reporting the error on awaitToken
       reportRecoverableError(inKeyword, codes.messageAwaitForNotAsync);
     }
 
-    listener.beginForInExpression(inKeyword.next);
+    listener.beginForInExpression(inKeyword.next!);
     token = parseExpression(inKeyword);
-    token = ensureCloseParen(token, forToken.next);
+    token = ensureCloseParen(token, forToken.next!);
     listener.endForInExpression(token);
     listener.handleForInLoopParts(
-        awaitToken, forToken, forToken.next, inKeyword);
+        awaitToken, forToken, forToken.next!, inKeyword);
     return token;
   }
 
@@ -6651,17 +6646,17 @@
   /// ;
   /// ```
   Token parseWhileStatement(Token token) {
-    Token whileToken = token.next;
+    Token whileToken = token.next!;
     assert(optional('while', whileToken));
     listener.beginWhileStatement(whileToken);
     token = ensureParenthesizedCondition(whileToken);
-    listener.beginWhileStatementBody(token.next);
+    listener.beginWhileStatementBody(token.next!);
     LoopState savedLoopState = loopState;
     loopState = LoopState.InsideLoop;
     token = parseStatement(token);
     loopState = savedLoopState;
-    listener.endWhileStatementBody(token.next);
-    listener.endWhileStatement(whileToken, token.next);
+    listener.endWhileStatementBody(token.next!);
+    listener.endWhileStatement(whileToken, token.next!);
     return token;
   }
 
@@ -6671,16 +6666,16 @@
   /// ;
   /// ```
   Token parseDoWhileStatement(Token token) {
-    Token doToken = token.next;
+    Token doToken = token.next!;
     assert(optional('do', doToken));
     listener.beginDoWhileStatement(doToken);
-    listener.beginDoWhileStatementBody(doToken.next);
+    listener.beginDoWhileStatementBody(doToken.next!);
     LoopState savedLoopState = loopState;
     loopState = LoopState.InsideLoop;
     token = parseStatement(doToken);
     loopState = savedLoopState;
     listener.endDoWhileStatementBody(token);
-    Token whileToken = token.next;
+    Token whileToken = token.next!;
     if (!optional('while', whileToken)) {
       reportRecoverableError(
           whileToken, codes.templateExpectedButGot.withArguments('while'));
@@ -6702,27 +6697,27 @@
         ensureBlock(token, /* template = */ null, blockKind.missingBlockName);
     listener.beginBlock(begin, blockKind);
     int statementCount = 0;
-    Token startToken = token.next;
+    Token startToken = token.next!;
     while (notEofOrValue('}', startToken)) {
       token = parseStatement(token);
-      if (identical(token.next, startToken)) {
+      if (identical(token.next!, startToken)) {
         // No progress was made, so we report the current token as being invalid
         // and move forward.
-        token = token.next;
+        token = token.next!;
         reportRecoverableError(
             token, codes.templateUnexpectedToken.withArguments(token));
       }
       ++statementCount;
-      startToken = token.next;
+      startToken = token.next!;
     }
-    token = token.next;
+    token = token.next!;
     assert(token.isEof || optional('}', token));
     listener.endBlock(statementCount, begin, token, blockKind);
     return token;
   }
 
   Token parseInvalidBlock(Token token) {
-    Token begin = token.next;
+    Token begin = token.next!;
     assert(optional('{', begin));
     // Parse and report the invalid block, but suppress errors
     // because an error has already been reported by the caller.
@@ -6742,11 +6737,11 @@
     //  does not modify the token stream. For now, use simple look ahead and
     //  ensure no false positives.
 
-    token = token.next;
+    token = token.next!;
     if (token.isIdentifier) {
-      token = token.next;
+      token = token.next!;
       if (optional('(', token)) {
-        token = token.endGroup.next;
+        token = token.endGroup!.next!;
         if (isOneOf(token, [';', '.', '..', '?', '?.'])) {
           return true;
         }
@@ -6772,7 +6767,7 @@
   /// Determine if the following tokens look like an 'await' expression
   /// and not a local variable or local function declaration.
   bool looksLikeAwaitExpression(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional('await', token));
 
     return looksLikeExpression(token);
@@ -6781,7 +6776,7 @@
   /// Determine if the following tokens look like a 'yield' expression and not a
   /// local variable or local function declaration.
   bool looksLikeYieldStatement(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional('yield', token));
 
     return looksLikeExpression(token);
@@ -6793,17 +6788,17 @@
   /// ;
   /// ```
   Token parseAwaitExpression(Token token, bool allowCascades) {
-    Token awaitToken = token.next;
+    Token awaitToken = token.next!;
     assert(optional('await', awaitToken));
     listener.beginAwaitExpression(awaitToken);
     token = parsePrecedenceExpression(
         awaitToken, POSTFIX_PRECEDENCE, allowCascades);
     if (inAsync) {
-      listener.endAwaitExpression(awaitToken, token.next);
+      listener.endAwaitExpression(awaitToken, token.next!);
     } else {
       codes.MessageCode errorCode = codes.messageAwaitNotAsync;
       reportRecoverableError(awaitToken, errorCode);
-      listener.endInvalidAwaitExpression(awaitToken, token.next, errorCode);
+      listener.endInvalidAwaitExpression(awaitToken, token.next!, errorCode);
     }
     return token;
   }
@@ -6818,23 +6813,23 @@
   /// ;
   /// ```
   Token parseThrowExpression(Token token, bool allowCascades) {
-    Token throwToken = token.next;
+    Token throwToken = token.next!;
     assert(optional('throw', throwToken));
-    if (optional(';', throwToken.next)) {
+    if (optional(';', throwToken.next!)) {
       // TODO(danrubel): Find a better way to intercept the parseExpression
       // recovery to generate this error message rather than explicitly
       // checking the next token as we are doing here.
       reportRecoverableError(
-          throwToken.next, codes.messageMissingExpressionInThrow);
+          throwToken.next!, codes.messageMissingExpressionInThrow);
       rewriter.insertToken(
           throwToken,
           new SyntheticStringToken(TokenType.STRING, '""',
-              throwToken.next.charOffset, /* _length = */ 0));
+              throwToken.next!.charOffset, /* _length = */ 0));
     }
     token = allowCascades
         ? parseExpression(throwToken)
         : parseExpressionWithoutCascade(throwToken);
-    listener.handleThrowExpression(throwToken, token.next);
+    listener.handleThrowExpression(throwToken, token.next!);
     return token;
   }
 
@@ -6844,7 +6839,7 @@
   /// ;
   /// ```
   Token parseRethrowStatement(Token token) {
-    Token throwToken = token.next;
+    Token throwToken = token.next!;
     assert(optional('rethrow', throwToken));
     listener.beginRethrowStatement(throwToken);
     token = ensureSemicolon(throwToken);
@@ -6871,47 +6866,47 @@
   /// ;
   /// ```
   Token parseTryStatement(Token token) {
-    Token tryKeyword = token.next;
+    Token tryKeyword = token.next!;
     assert(optional('try', tryKeyword));
     listener.beginTryStatement(tryKeyword);
     Token lastConsumed = parseBlock(tryKeyword, BlockKind.tryStatement);
-    token = lastConsumed.next;
+    token = lastConsumed.next!;
     int catchCount = 0;
 
-    String value = token.stringValue;
+    String? value = token.stringValue;
     while (identical(value, 'catch') || identical(value, 'on')) {
       listener.beginCatchClause(token);
-      Token onKeyword = null;
+      Token? onKeyword = null;
       if (identical(value, 'on')) {
         // 'on' type catchPart?
         onKeyword = token;
         lastConsumed = computeType(token, /* required = */ true)
             .ensureTypeNotVoid(token, this);
-        token = lastConsumed.next;
+        token = lastConsumed.next!;
         value = token.stringValue;
       }
-      Token catchKeyword = null;
-      Token comma = null;
+      Token? catchKeyword = null;
+      Token? comma = null;
       if (identical(value, 'catch')) {
         catchKeyword = token;
 
-        Token openParens = catchKeyword.next;
+        Token openParens = catchKeyword.next!;
         if (!optional("(", openParens)) {
           reportRecoverableError(openParens, codes.messageCatchSyntax);
           openParens = rewriter.insertParens(
               catchKeyword, /* includeIdentifier = */ true);
         }
 
-        Token exceptionName = openParens.next;
+        Token exceptionName = openParens.next!;
         if (exceptionName.kind != IDENTIFIER_TOKEN) {
           exceptionName = IdentifierContext.catchParameter
               .ensureIdentifier(openParens, this);
         }
 
-        if (optional(")", exceptionName.next)) {
+        if (optional(")", exceptionName.next!)) {
           // OK: `catch (identifier)`.
         } else {
-          comma = exceptionName.next;
+          comma = exceptionName.next!;
           if (!optional(",", comma)) {
             // Recovery
             if (!exceptionName.isSynthetic) {
@@ -6939,9 +6934,9 @@
             //   } catch (e) {}
             //   _s_.f();
 
-            if (openParens.endGroup.isSynthetic) {
+            if (openParens.endGroup!.isSynthetic) {
               // The scanner did not place the synthetic ')' correctly.
-              rewriter.moveSynthetic(exceptionName, openParens.endGroup);
+              rewriter.moveSynthetic(exceptionName, openParens.endGroup!);
               comma = null;
             } else {
               comma =
@@ -6949,40 +6944,40 @@
             }
           }
           if (comma != null) {
-            Token traceName = comma.next;
+            Token traceName = comma.next!;
             if (traceName.kind != IDENTIFIER_TOKEN) {
               traceName = IdentifierContext.catchParameter
                   .ensureIdentifier(comma, this);
             }
-            if (!optional(")", traceName.next)) {
+            if (!optional(")", traceName.next!)) {
               // Recovery
               if (!traceName.isSynthetic) {
                 reportRecoverableError(
-                    traceName.next, codes.messageCatchSyntaxExtraParameters);
+                    traceName.next!, codes.messageCatchSyntaxExtraParameters);
               }
-              if (openParens.endGroup.isSynthetic) {
+              if (openParens.endGroup!.isSynthetic) {
                 // The scanner did not place the synthetic ')' correctly.
-                rewriter.moveSynthetic(traceName, openParens.endGroup);
+                rewriter.moveSynthetic(traceName, openParens.endGroup!);
               }
             }
           }
         }
         lastConsumed = parseFormalParameters(catchKeyword, MemberKind.Catch);
-        token = lastConsumed.next;
+        token = lastConsumed.next!;
       }
       listener.endCatchClause(token);
       lastConsumed = parseBlock(lastConsumed, BlockKind.catchClause);
-      token = lastConsumed.next;
+      token = lastConsumed.next!;
       ++catchCount;
       listener.handleCatchBlock(onKeyword, catchKeyword, comma);
       value = token.stringValue; // while condition
     }
 
-    Token finallyKeyword = null;
+    Token? finallyKeyword = null;
     if (optional('finally', token)) {
       finallyKeyword = token;
       lastConsumed = parseBlock(token, BlockKind.finallyClause);
-      token = lastConsumed.next;
+      token = lastConsumed.next!;
       listener.handleFinallyBlock(finallyKeyword);
     } else {
       if (catchCount == 0) {
@@ -6999,7 +6994,7 @@
   /// ;
   /// ```
   Token parseSwitchStatement(Token token) {
-    Token switchKeyword = token.next;
+    Token switchKeyword = token.next!;
     assert(optional('switch', switchKeyword));
     listener.beginSwitchStatement(switchKeyword);
     token = ensureParenthesizedCondition(switchKeyword);
@@ -7023,35 +7018,35 @@
         token = ensureBlock(token, /* template = */ null, 'switch statement');
     listener.beginSwitchBlock(beginSwitch);
     int caseCount = 0;
-    Token defaultKeyword = null;
-    Token colonAfterDefault = null;
-    while (notEofOrValue('}', token.next)) {
-      Token beginCase = token.next;
+    Token? defaultKeyword = null;
+    Token? colonAfterDefault = null;
+    while (notEofOrValue('}', token.next!)) {
+      Token beginCase = token.next!;
       int expressionCount = 0;
       int labelCount = 0;
       Token peek = peekPastLabels(beginCase);
       while (true) {
         // Loop until we find something that can't be part of a switch case.
-        String value = peek.stringValue;
+        String? value = peek.stringValue;
         if (identical(value, 'default')) {
-          while (!identical(token.next, peek)) {
+          while (!identical(token.next!, peek)) {
             token = parseLabel(token);
             labelCount++;
           }
           if (defaultKeyword != null) {
             reportRecoverableError(
-                token.next, codes.messageSwitchHasMultipleDefaults);
+                token.next!, codes.messageSwitchHasMultipleDefaults);
           }
-          defaultKeyword = token.next;
+          defaultKeyword = token.next!;
           colonAfterDefault = token = ensureColon(defaultKeyword);
-          peek = token.next;
+          peek = token.next!;
           break;
         } else if (identical(value, 'case')) {
-          while (!identical(token.next, peek)) {
+          while (!identical(token.next!, peek)) {
             token = parseLabel(token);
             labelCount++;
           }
-          Token caseKeyword = token.next;
+          Token caseKeyword = token.next!;
           if (defaultKeyword != null) {
             reportRecoverableError(
                 caseKeyword, codes.messageSwitchHasCaseAfterDefault);
@@ -7062,18 +7057,18 @@
           listener.endCaseExpression(token);
           listener.handleCaseMatch(caseKeyword, token);
           expressionCount++;
-          peek = peekPastLabels(token.next);
+          peek = peekPastLabels(token.next!);
         } else if (expressionCount > 0) {
           break;
         } else {
           // Recovery
           reportRecoverableError(
               peek, codes.templateExpectedToken.withArguments("case"));
-          Token endGroup = beginSwitch.endGroup;
+          Token endGroup = beginSwitch.endGroup!;
           while (token.next != endGroup) {
-            token = token.next;
+            token = token.next!;
           }
-          peek = peekPastLabels(token.next);
+          peek = peekPastLabels(token.next!);
           break;
         }
       }
@@ -7081,7 +7076,7 @@
           expressionCount, defaultKeyword, colonAfterDefault);
       ++caseCount;
     }
-    token = token.next;
+    token = token.next!;
     listener.endSwitchBlock(caseCount, beginSwitch, token);
     assert(token.isEof || optional('}', token));
     return token;
@@ -7091,8 +7086,8 @@
   /// is used to determine if the labels belong to a statement or a
   /// switch case.
   Token peekPastLabels(Token token) {
-    while (token.isIdentifier && optional(':', token.next)) {
-      token = token.next.next;
+    while (token.isIdentifier && optional(':', token.next!)) {
+      token = token.next!.next!;
     }
     return token;
   }
@@ -7104,22 +7099,22 @@
       Token begin,
       int labelCount,
       int expressionCount,
-      Token defaultKeyword,
-      Token colonAfterDefault) {
+      Token? defaultKeyword,
+      Token? colonAfterDefault) {
     listener.beginSwitchCase(labelCount, expressionCount, begin);
     // Finally zero or more statements.
     int statementCount = 0;
-    while (!identical(token.next.kind, EOF_TOKEN)) {
-      String value = peek.stringValue;
+    while (!identical(token.next!.kind, EOF_TOKEN)) {
+      String? value = peek.stringValue;
       if ((identical(value, 'case')) ||
           (identical(value, 'default')) ||
-          ((identical(value, '}')) && (identical(token.next, peek)))) {
+          ((identical(value, '}')) && (identical(token.next!, peek)))) {
         // A label just before "}" will be handled as a statement error.
         break;
       } else {
-        Token startToken = token.next;
+        Token startToken = token.next!;
         token = parseStatement(token);
-        Token next = token.next;
+        Token next = token.next!;
         if (identical(next, startToken)) {
           // No progress was made, so we report the current token as being
           // invalid and move forward.
@@ -7129,10 +7124,10 @@
         }
         ++statementCount;
       }
-      peek = peekPastLabels(token.next);
+      peek = peekPastLabels(token.next!);
     }
     listener.endSwitchCase(labelCount, expressionCount, defaultKeyword,
-        colonAfterDefault, statementCount, begin, token.next);
+        colonAfterDefault, statementCount, begin, token.next!);
     return token;
   }
 
@@ -7142,10 +7137,10 @@
   /// ;
   /// ```
   Token parseBreakStatement(Token token) {
-    Token breakKeyword = token = token.next;
+    Token breakKeyword = token = token.next!;
     assert(optional('break', breakKeyword));
     bool hasTarget = false;
-    if (token.next.isIdentifier) {
+    if (token.next!.isIdentifier) {
       token = ensureIdentifier(token, IdentifierContext.labelReference);
       hasTarget = true;
     } else if (!isBreakAllowed) {
@@ -7162,11 +7157,11 @@
   /// ;
   /// ```
   Token parseAssert(Token token, Assert kind) {
-    token = token.next;
+    token = token.next!;
     assert(optional('assert', token));
     listener.beginAssert(token, kind);
     Token assertKeyword = token;
-    Token leftParenthesis = token.next;
+    Token leftParenthesis = token.next!;
     if (!optional('(', leftParenthesis)) {
       // Recovery
       reportRecoverableError(
@@ -7175,24 +7170,24 @@
           rewriter.insertParens(token, /* includeIdentifier = */ true);
     }
     token = leftParenthesis;
-    Token commaToken = null;
+    Token? commaToken = null;
     bool old = mayParseFunctionExpressions;
     mayParseFunctionExpressions = true;
 
     token = parseExpression(token);
-    if (optional(',', token.next)) {
-      token = token.next;
-      if (!optional(')', token.next)) {
+    if (optional(',', token.next!)) {
+      token = token.next!;
+      if (!optional(')', token.next!)) {
         commaToken = token;
         token = parseExpression(token);
-        if (optional(',', token.next)) {
+        if (optional(',', token.next!)) {
           // Trailing comma is ignored.
-          token = token.next;
+          token = token.next!;
         }
       }
     }
 
-    Token endGroup = leftParenthesis.endGroup;
+    Token endGroup = leftParenthesis.endGroup!;
     if (token.next == endGroup) {
       token = endGroup;
     } else {
@@ -7202,7 +7197,7 @@
         token = rewriter.moveSynthetic(token, endGroup);
       } else {
         reportRecoverableErrorWithToken(
-            token.next, codes.templateUnexpectedToken);
+            token.next!, codes.templateUnexpectedToken);
         token = endGroup;
       }
     }
@@ -7215,7 +7210,7 @@
       ensureSemicolon(token);
     }
     listener.endAssert(
-        assertKeyword, kind, leftParenthesis, commaToken, token.next);
+        assertKeyword, kind, leftParenthesis, commaToken, token.next!);
     return token;
   }
 
@@ -7225,9 +7220,9 @@
   /// ;
   /// ```
   Token parseAssertStatement(Token token) {
-    assert(optional('assert', token.next));
+    assert(optional('assert', token.next!));
     // parseAssert ensures that there is a trailing semicolon.
-    return parseAssert(token, Assert.Statement).next;
+    return parseAssert(token, Assert.Statement).next!;
   }
 
   /// ```
@@ -7236,10 +7231,10 @@
   /// ;
   /// ```
   Token parseContinueStatement(Token token) {
-    Token continueKeyword = token = token.next;
+    Token continueKeyword = token = token.next!;
     assert(optional('continue', continueKeyword));
     bool hasTarget = false;
-    if (token.next.isIdentifier) {
+    if (token.next!.isIdentifier) {
       token = ensureIdentifier(token, IdentifierContext.labelReference);
       hasTarget = true;
       if (!isContinueWithLabelAllowed) {
@@ -7264,7 +7259,7 @@
   /// ;
   /// ```
   Token parseEmptyStatement(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional(';', token));
     listener.handleEmptyStatement(token);
     return token;
@@ -7273,10 +7268,10 @@
   /// Given a token ([beforeToken]) that is known to be before another [token],
   /// return the token that is immediately before the [token].
   Token previousToken(Token beforeToken, Token token) {
-    Token next = beforeToken.next;
+    Token next = beforeToken.next!;
     while (next != token && next != beforeToken) {
       beforeToken = next;
-      next = beforeToken.next;
+      next = beforeToken.next!;
     }
     return beforeToken;
   }
@@ -7286,29 +7281,29 @@
   /// (and events have already been generated).
   Token parseInvalidOperatorDeclaration(
       Token beforeStart,
-      Token abstractToken,
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       Token beforeType,
       DeclarationKind kind,
-      String enclosingDeclarationName) {
+      String? enclosingDeclarationName) {
     TypeInfo typeInfo = computeType(
         beforeStart, /* required = */ false, /* inDeclaration = */ true);
     Token beforeName = typeInfo.skipType(beforeType);
-    Token next = beforeName.next;
+    Token next = beforeName.next!;
 
     if (optional('operator', next)) {
-      next = next.next;
+      next = next.next!;
     } else {
       // The 'operator' keyword is missing, but we may or may not have a type
       // before the token that is the actual operator.
       Token operator = next;
-      if (!next.isOperator && next.next.isOperator) {
+      if (!next.isOperator && next.next!.isOperator) {
         beforeName = next;
-        operator = next.next;
+        operator = next.next!;
       }
       reportRecoverableError(operator, codes.messageMissingOperatorKeyword);
       rewriter.insertSyntheticKeyword(beforeName, Keyword.OPERATOR);
@@ -7317,14 +7312,14 @@
       typeInfo = computeType(
           beforeStart, /* required = */ true, /* inDeclaration = */ true);
       beforeName = typeInfo.skipType(beforeType);
-      next = beforeName.next;
+      next = beforeName.next!;
 
       // The 'next' token can be the just-inserted 'operator' keyword.
       // If it is, change it so it points to the actual operator.
       if (!next.isOperator &&
-          next.next.isOperator &&
+          next.next!.isOperator &&
           identical(next.stringValue, 'operator')) {
-        next = next.next;
+        next = next.next!;
       }
     }
 
@@ -7343,7 +7338,7 @@
         beforeType,
         typeInfo,
         /* getOrSet = */ null,
-        beforeName.next,
+        beforeName.next!,
         kind,
         enclosingDeclarationName,
         /* nameIsRecovered = */ false);
@@ -7357,19 +7352,19 @@
   Token recoverFromInvalidMember(
       Token token,
       Token beforeStart,
-      Token abstractToken,
-      Token externalToken,
-      Token staticToken,
-      Token covariantToken,
-      Token lateToken,
-      Token varFinalOrConst,
+      Token? abstractToken,
+      Token? externalToken,
+      Token? staticToken,
+      Token? covariantToken,
+      Token? lateToken,
+      Token? varFinalOrConst,
       Token beforeType,
       TypeInfo typeInfo,
-      Token getOrSet,
+      Token? getOrSet,
       DeclarationKind kind,
-      String enclosingDeclarationName) {
-    Token next = token.next;
-    String value = next.stringValue;
+      String? enclosingDeclarationName) {
+    Token next = token.next!;
+    String? value = next.stringValue;
 
     if (identical(value, 'class')) {
       return reportAndSkipClassInClass(next);
@@ -7406,7 +7401,7 @@
           beforeType,
           typeInfo,
           getOrSet,
-          token.next,
+          token.next!,
           kind,
           enclosingDeclarationName,
           /* nameIsRecovered = */ false);
@@ -7429,7 +7424,7 @@
           varFinalOrConst,
           beforeType,
           typeInfo,
-          token.next,
+          token.next!,
           kind,
           enclosingDeclarationName,
           /* nameIsRecovered = */ false);
@@ -7442,14 +7437,14 @@
   /// Report that the nesting depth of the code being parsed is too large for
   /// the parser to safely handle. Return the next `}` or EOF.
   Token recoverFromStackOverflow(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     reportRecoverableError(next, codes.messageStackOverflow);
     next = rewriter.insertSyntheticToken(token, TokenType.SEMICOLON);
     listener.handleEmptyStatement(next);
 
     while (notEofOrValue('}', next)) {
       token = next;
-      next = token.next;
+      next = token.next!;
     }
     return token;
   }
@@ -7476,20 +7471,20 @@
   Token reportAllErrorTokens(Token token) {
     while (token is ErrorToken) {
       listener.handleErrorToken(token);
-      token = token.next;
+      token = token.next!;
     }
     return token;
   }
 
   Token skipErrorTokens(Token token) {
     while (token is ErrorToken) {
-      token = token.next;
+      token = token.next!;
     }
     return token;
   }
 
   Token parseInvalidTopLevelDeclaration(Token token) {
-    Token next = token.next;
+    Token next = token.next!;
     reportRecoverableErrorWithToken(
         next,
         optional(';', next)
@@ -7506,19 +7501,19 @@
     assert(optional('class', token));
     reportRecoverableError(token, codes.messageClassInClass);
     listener.handleInvalidMember(token);
-    Token next = token.next;
+    Token next = token.next!;
     // If the declaration appears to be a valid class declaration
     // then skip the entire declaration so that we only generate the one
     // error (above) rather than a plethora of unhelpful errors.
     if (next.isIdentifier) {
       // skip class name
       token = next;
-      next = token.next;
+      next = token.next!;
       // TODO(danrubel): consider parsing (skipping) the class header
       // with a recovery listener so that no events are generated
       if (optional('{', next) && next.endGroup != null) {
         // skip class body
-        token = next.endGroup;
+        token = next.endGroup!;
       }
     }
     listener.endMember();
@@ -7529,19 +7524,19 @@
     assert(optional('enum', token));
     reportRecoverableError(token, codes.messageEnumInClass);
     listener.handleInvalidMember(token);
-    Token next = token.next;
+    Token next = token.next!;
     // If the declaration appears to be a valid enum declaration
     // then skip the entire declaration so that we only generate the one
     // error (above) rather than a plethora of unhelpful errors.
     if (next.isIdentifier) {
       // skip enum name
       token = next;
-      next = token.next;
+      next = token.next!;
       if (optional('{', next) && next.endGroup != null) {
         // TODO(danrubel): Consider replacing this `skip enum` functionality
         // with something that can parse and resolve the declaration
         // even though it is in a class context
-        token = next.endGroup;
+        token = next.endGroup!;
       }
     }
     listener.endMember();
@@ -7575,7 +7570,7 @@
     // use and return the last token consumed and the `previous` field
     // has been removed.
     if (token.previous != null) {
-      return token.previous;
+      return token.previous!;
     }
     Token before = new Token.eof(/* offset = */ -1);
     before.next = token;
@@ -7584,9 +7579,9 @@
 
   /// Return the first dartdoc comment token preceding the given token
   /// or `null` if no dartdoc token is found.
-  Token findDartDoc(Token token) {
-    Token comments = token.precedingComments;
-    Token dartdoc = null;
+  Token? findDartDoc(Token token) {
+    Token? comments = token.precedingComments;
+    Token? dartdoc = null;
     bool isMultiline = false;
     while (comments != null) {
       String lexeme = comments.lexeme;
@@ -7653,7 +7648,7 @@
   /// Parse the comment references in a sequence of single line comment tokens
   /// where [token] is the first comment token in the sequence.
   /// Return the number of comment references parsed.
-  int parseReferencesInSingleLineComments(Token token) {
+  int parseReferencesInSingleLineComments(Token? token) {
     int count = 0;
     bool inCodeBlock = false;
     while (token != null && !token.isEof) {
@@ -7752,45 +7747,45 @@
   /// Return `true` if a comment reference was successfully parsed.
   bool parseOneCommentReference(Token token, int referenceOffset) {
     Token begin = token;
-    Token newKeyword = null;
+    Token? newKeyword = null;
     if (optional('new', token)) {
       newKeyword = token;
-      token = token.next;
+      token = token.next!;
     }
-    Token prefix, period;
-    if (token.isIdentifier && optional('.', token.next)) {
+    Token? prefix, period;
+    if (token.isIdentifier && optional('.', token.next!)) {
       prefix = token;
-      period = token.next;
-      token = period.next;
+      period = token.next!;
+      token = period.next!;
     }
     if (token.isEof) {
       // Recovery: Insert a synthetic identifier for code completion
       token = rewriter.insertSyntheticIdentifier(
           period ?? newKeyword ?? syntheticPreviousToken(token));
-      if (begin == token.next) {
+      if (begin == token.next!) {
         begin = token;
       }
     }
-    Token operatorKeyword = null;
+    Token? operatorKeyword = null;
     if (optional('operator', token)) {
       operatorKeyword = token;
-      token = token.next;
+      token = token.next!;
     }
     if (token.isUserDefinableOperator) {
-      if (token.next.isEof) {
+      if (token.next!.isEof) {
         parseOneCommentReferenceRest(
             begin, referenceOffset, newKeyword, prefix, period, token);
         return true;
       }
     } else {
       token = operatorKeyword ?? token;
-      if (token.next.isEof) {
+      if (token.next!.isEof) {
         if (token.isIdentifier) {
           parseOneCommentReferenceRest(
               begin, referenceOffset, newKeyword, prefix, period, token);
           return true;
         }
-        Keyword keyword = token.keyword;
+        Keyword? keyword = token.keyword;
         if (newKeyword == null &&
             prefix == null &&
             (keyword == Keyword.THIS ||
@@ -7812,15 +7807,15 @@
   void parseOneCommentReferenceRest(
       Token begin,
       int referenceOffset,
-      Token newKeyword,
-      Token prefix,
-      Token period,
+      Token? newKeyword,
+      Token? prefix,
+      Token? period,
       Token identifierOrOperator) {
     // Adjust the token offsets to match the enclosing comment token.
     Token token = begin;
     do {
       token.offset += referenceOffset;
-      token = token.next;
+      token = token.next!;
     } while (!token.isEof);
 
     listener.handleCommentReference(
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/quote.dart b/pkg/_fe_analyzer_shared/lib/src/parser/quote.dart
index a33410d..0d5b048 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/quote.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/quote.dart
@@ -102,7 +102,6 @@
     case Quote.RawMultiLineDouble:
       return lengthOfOptionalWhitespacePrefix(first, /* start = */ 4);
   }
-  return throw new UnsupportedError("'$quote' in  firstQuoteLength");
 }
 
 int lastQuoteLength(Quote quote) {
@@ -119,7 +118,6 @@
     case Quote.RawMultiLineDouble:
       return 3;
   }
-  return throw new UnsupportedError("'$quote' in lastQuoteLength");
 }
 
 String unescapeFirstStringPart(String first, Quote quote, Object location,
@@ -176,7 +174,6 @@
           : unescapeCodeUnits(
               string.codeUnits, /* isRaw = */ true, location, listener);
   }
-  return throw new UnsupportedError("'$quote' in unescape");
 }
 
 // Note: based on
@@ -184,7 +181,7 @@
 String unescapeCodeUnits(List<int> codeUnits, bool isRaw, Object location,
     UnescapeErrorListener listener) {
   // Can't use Uint8List or Uint16List here, the code units may be larger.
-  List<int> result = new List<int>.filled(codeUnits.length, null);
+  List<int> result = new List<int>.filled(codeUnits.length, 0);
   int resultOffset = 0;
 
   for (int i = 0; i < codeUnits.length; i++) {
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/recovery_listeners.dart b/pkg/_fe_analyzer_shared/lib/src/parser/recovery_listeners.dart
index 9320871..5c24c53 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/recovery_listeners.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/recovery_listeners.dart
@@ -7,9 +7,9 @@
 import 'forwarding_listener.dart' show ForwardingListener;
 
 class ClassHeaderRecoveryListener extends ForwardingListener {
-  Token extendsKeyword;
-  Token implementsKeyword;
-  Token withKeyword;
+  Token? extendsKeyword;
+  Token? implementsKeyword;
+  Token? withKeyword;
 
   void clear() {
     extendsKeyword = null;
@@ -18,14 +18,14 @@
   }
 
   @override
-  void handleClassExtends(Token extendsKeyword, int typeCount) {
+  void handleClassExtends(Token? extendsKeyword, int typeCount) {
     this.extendsKeyword = extendsKeyword;
     super.handleClassExtends(extendsKeyword, typeCount);
   }
 
   @override
   void handleClassOrMixinImplements(
-      Token implementsKeyword, int interfacesCount) {
+      Token? implementsKeyword, int interfacesCount) {
     this.implementsKeyword = implementsKeyword;
     super.handleClassOrMixinImplements(implementsKeyword, interfacesCount);
   }
@@ -38,9 +38,9 @@
 }
 
 class ImportRecoveryListener extends ForwardingListener {
-  Token asKeyword;
-  Token deferredKeyword;
-  Token ifKeyword;
+  Token? asKeyword;
+  Token? deferredKeyword;
+  Token? ifKeyword;
   bool hasCombinator = false;
 
   void clear() {
@@ -50,7 +50,7 @@
     hasCombinator = false;
   }
 
-  void endConditionalUri(Token ifKeyword, Token leftParen, Token equalSign) {
+  void endConditionalUri(Token ifKeyword, Token leftParen, Token? equalSign) {
     this.ifKeyword = ifKeyword;
     super.endConditionalUri(ifKeyword, leftParen, equalSign);
   }
@@ -65,7 +65,7 @@
     super.endShow(showKeyword);
   }
 
-  void handleImportPrefix(Token deferredKeyword, Token asKeyword) {
+  void handleImportPrefix(Token? deferredKeyword, Token? asKeyword) {
     this.deferredKeyword = deferredKeyword;
     this.asKeyword = asKeyword;
     super.handleImportPrefix(deferredKeyword, asKeyword);
@@ -73,8 +73,8 @@
 }
 
 class MixinHeaderRecoveryListener extends ForwardingListener {
-  Token onKeyword;
-  Token implementsKeyword;
+  Token? onKeyword;
+  Token? implementsKeyword;
 
   void clear() {
     onKeyword = null;
@@ -83,13 +83,13 @@
 
   @override
   void handleClassOrMixinImplements(
-      Token implementsKeyword, int interfacesCount) {
+      Token? implementsKeyword, int interfacesCount) {
     this.implementsKeyword = implementsKeyword;
     super.handleClassOrMixinImplements(implementsKeyword, interfacesCount);
   }
 
   @override
-  void handleMixinOn(Token onKeyword, int typeCount) {
+  void handleMixinOn(Token? onKeyword, int typeCount) {
     this.onKeyword = onKeyword;
     super.handleMixinOn(onKeyword, typeCount);
   }
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
index 6462add..ce64454 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
@@ -75,7 +75,7 @@
   final Stack stack = debugStack ? new DebugStack() : new StackImpl();
 
   /// Used to report an internal error encountered in the stack listener.
-  dynamic internalProblem(Message message, int charOffset, Uri uri);
+  Never internalProblem(Message message, int charOffset, Uri uri);
 
   /// Checks that [value] matches the expected [kind].
   ///
@@ -84,15 +84,17 @@
   ///     assert(checkValue(token, ValueKind.Token, value));
   ///
   /// to document and validate the expected value kind.
-  bool checkValue(Token token, ValueKind kind, Object value) {
+  bool checkValue(Token? token, ValueKind kind, Object value) {
     if (!kind.check(value)) {
       String message = 'Unexpected value `${value}` (${value.runtimeType}). '
           'Expected ${kind}.';
       if (token != null) {
         // If offset is available report and internal problem to show the
         // parsed code in the output.
-        throw internalProblem(new Message(/* code = */ null, message: message),
-            token.charOffset, uri);
+        throw internalProblem(
+            new Message(const Code<String>('Internal error'), message: message),
+            token.charOffset,
+            uri);
       } else {
         throw message;
       }
@@ -110,12 +112,12 @@
   ///
   /// to document the expected stack and get earlier errors on unexpected stack
   /// content.
-  bool checkState(Token token, List<ValueKind> kinds) {
+  bool checkState(Token? token, List<ValueKind> kinds) {
     bool success = true;
     for (int kindIndex = 0; kindIndex < kinds.length; kindIndex++) {
       ValueKind kind = kinds[kindIndex];
       if (kindIndex < stack.length) {
-        Object value = stack[kindIndex];
+        Object? value = stack[kindIndex];
         if (!kind.check(value)) {
           success = false;
         }
@@ -126,7 +128,7 @@
     if (!success) {
       StringBuffer sb = new StringBuffer();
 
-      String safeToString(Object object) {
+      String safeToString(Object? object) {
         try {
           return '$object';
         } catch (e) {
@@ -160,7 +162,7 @@
         }
         sb.write(padLeft(kindIndex, 4));
         sb.write(': ');
-        ValueKind kind;
+        ValueKind? kind;
         if (kindIndex < kinds.length) {
           kind = kinds[kindIndex];
           sb.write(padRight(kind, 60));
@@ -168,7 +170,7 @@
           sb.write(padRight('---', 60));
         }
         if (kindIndex < stack.length) {
-          Object value = stack[kindIndex];
+          Object? value = stack[kindIndex];
           if (kind == null || kind.check(value)) {
             sb.write(' ');
           } else {
@@ -191,8 +193,10 @@
       if (token != null) {
         // If offset is available report and internal problem to show the
         // parsed code in the output.
-        throw internalProblem(new Message(/* code = */ null, message: message),
-            token.charOffset, uri);
+        throw internalProblem(
+            new Message(const Code<String>('Internal error'), message: message),
+            token.charOffset,
+            uri);
       } else {
         throw message;
       }
@@ -209,7 +213,7 @@
     }
   }
 
-  void push(Object node) {
+  void push(Object? node) {
     if (node == null) {
       internalProblem(
           templateInternalProblemUnhandled.withArguments("null", "push"),
@@ -219,17 +223,17 @@
     stack.push(node);
   }
 
-  void pushIfNull(Token tokenOrNull, NullValue nullValue) {
+  void pushIfNull(Token? tokenOrNull, NullValue nullValue) {
     if (tokenOrNull == null) stack.push(nullValue);
   }
 
-  Object peek() => stack.isNotEmpty ? stack.last : null;
+  Object? peek() => stack.isNotEmpty ? stack.last : null;
 
-  Object pop([NullValue nullValue]) {
+  Object? pop([NullValue? nullValue]) {
     return stack.pop(nullValue);
   }
 
-  Object popIfNotNull(Object value) {
+  Object? popIfNotNull(Object? value) {
     return value == null ? null : pop();
   }
 
@@ -239,7 +243,7 @@
 
   void printEvent(String name) {
     print('\n------------------');
-    for (Object o in stack.values) {
+    for (Object? o in stack.values) {
       String s = "  $o";
       int index = s.indexOf("\n");
       if (index != -1) {
@@ -306,17 +310,17 @@
   }
 
   @override
-  void handleClassExtends(Token extendsKeyword, int typeCount) {
+  void handleClassExtends(Token? extendsKeyword, int typeCount) {
     debugEvent("ClassExtends");
   }
 
   @override
-  void handleMixinOn(Token onKeyword, int typeCount) {
+  void handleMixinOn(Token? onKeyword, int typeCount) {
     debugEvent("MixinOn");
   }
 
   @override
-  void handleClassHeader(Token begin, Token classKeyword, Token nativeToken) {
+  void handleClassHeader(Token begin, Token classKeyword, Token? nativeToken) {
     debugEvent("ClassHeader");
   }
 
@@ -337,7 +341,7 @@
 
   @override
   void handleClassOrMixinImplements(
-      Token implementsKeyword, int interfacesCount) {
+      Token? implementsKeyword, int interfacesCount) {
     debugEvent("ClassImplements");
   }
 
@@ -424,7 +428,7 @@
   void endLiteralString(int interpolationCount, Token endToken) {
     debugEvent("endLiteralString");
     if (interpolationCount == 0) {
-      Token token = pop();
+      Token token = pop() as Token;
       push(unescapeString(token.lexeme, token, this));
     } else {
       internalProblem(
@@ -498,39 +502,39 @@
 abstract class Stack {
   /// Pops [count] elements from the stack and puts it into [list].
   /// Returns [null] if a [ParserRecovery] value is found, or [list] otherwise.
-  List<Object> popList(int count, List<Object> list, NullValue nullValue);
+  List<T?>? popList<T>(int count, List<T?> list, NullValue? nullValue);
 
   void push(Object value);
 
   /// Will return [null] instead of [NullValue].
-  Object get last;
+  Object? get last;
 
   bool get isNotEmpty;
 
-  List<Object> get values;
+  List<Object?> get values;
 
-  Object pop(NullValue nullValue);
+  Object? pop(NullValue? nullValue);
 
   int get length;
 
   /// Raw, i.e. [NullValue]s will be returned instead of [null].
-  Object operator [](int index);
+  Object? operator [](int index);
 }
 
 class StackImpl implements Stack {
-  List<Object> array = new List<Object>.filled(/* length = */ 8, null);
+  List<Object?> array = new List<Object?>.filled(/* length = */ 8, null);
   int arrayLength = 0;
 
   bool get isNotEmpty => arrayLength > 0;
 
   int get length => arrayLength;
 
-  Object get last {
-    final Object value = array[arrayLength - 1];
+  Object? get last {
+    final Object? value = array[arrayLength - 1];
     return value is NullValue ? null : value;
   }
 
-  Object operator [](int index) {
+  Object? operator [](int index) {
     return array[arrayLength - 1 - index];
   }
 
@@ -541,9 +545,9 @@
     }
   }
 
-  Object pop(NullValue nullValue) {
+  Object? pop(NullValue? nullValue) {
     assert(arrayLength > 0);
-    final Object value = array[--arrayLength];
+    final Object? value = array[--arrayLength];
     array[arrayLength] = null;
     if (value is! NullValue) {
       return value;
@@ -554,15 +558,15 @@
     }
   }
 
-  List<Object> popList(int count, List<Object> list, NullValue nullValue) {
+  List<T?>? popList<T>(int count, List<T?> list, NullValue? nullValue) {
     assert(arrayLength >= count);
-    final List<Object> array = this.array;
+    final List<Object?> array = this.array;
     final int length = arrayLength;
     final int startIndex = length - count;
     bool isParserRecovery = false;
     for (int i = 0; i < count; i++) {
       int arrayIndex = startIndex + i;
-      final Object value = array[arrayIndex];
+      final Object? value = array[arrayIndex];
       array[arrayIndex] = null;
       if (value is NullValue && nullValue == null ||
           identical(value, nullValue)) {
@@ -571,7 +575,7 @@
         isParserRecovery = true;
       } else {
         assert(value is! NullValue);
-        list[i] = value;
+        list[i] = value as T;
       }
     }
     arrayLength -= count;
@@ -579,16 +583,16 @@
     return isParserRecovery ? null : list;
   }
 
-  List<Object> get values {
+  List<Object?> get values {
     final int length = arrayLength;
-    final List<Object> list = new List<Object>.filled(length, null);
+    final List<Object?> list = new List<Object?>.filled(length, null);
     list.setRange(/* start = */ 0, length, array);
     return list;
   }
 
   void _grow() {
     final int length = array.length;
-    final List<Object> newArray = new List<Object>.filled(length * 2, null);
+    final List<Object?> newArray = new List<Object?>.filled(length * 2, null);
     newArray.setRange(/* start = */ 0, length, array, /* skipCount = */ 0);
     array = newArray;
   }
@@ -600,10 +604,10 @@
   List<StackTrace> latestStacktraces = <StackTrace>[];
 
   @override
-  Object operator [](int index) {
-    Object result = realStack[index];
+  Object? operator [](int index) {
+    Object? result = realStack[index];
     latestStacktraces.clear();
-    latestStacktraces.add(stackTraceStack[index]);
+    latestStacktraces.add(stackTraceStack[index] as StackTrace);
     return result;
   }
 
@@ -611,8 +615,8 @@
   bool get isNotEmpty => realStack.isNotEmpty;
 
   @override
-  Object get last {
-    Object result = this[0];
+  Object? get last {
+    Object? result = this[0];
     if (result is NullValue) return null;
     return result;
   }
@@ -621,16 +625,17 @@
   int get length => realStack.length;
 
   @override
-  Object pop(NullValue nullValue) {
-    Object result = realStack.pop(nullValue);
+  Object? pop(NullValue? nullValue) {
+    Object? result = realStack.pop(nullValue);
     latestStacktraces.clear();
-    latestStacktraces.add(stackTraceStack.pop(/* nullValue = */ null));
+    latestStacktraces
+        .add(stackTraceStack.pop(/* nullValue = */ null) as StackTrace);
     return result;
   }
 
   @override
-  List<Object> popList(int count, List<Object> list, NullValue nullValue) {
-    List<Object> result = realStack.popList(count, list, nullValue);
+  List<T?>? popList<T>(int count, List<T?> list, NullValue? nullValue) {
+    List<T?>? result = realStack.popList(count, list, nullValue);
     latestStacktraces.length = count;
     stackTraceStack.popList(count, latestStacktraces, /* nullValue = */ null);
     return result;
@@ -643,7 +648,7 @@
   }
 
   @override
-  List<Object> get values => realStack.values;
+  List<Object?> get values => realStack.values;
 }
 
 /// Helper constant for popping a list of the top of a [Stack].  This helper
@@ -652,16 +657,16 @@
 class FixedNullableList<T> {
   const FixedNullableList();
 
-  List<T> pop(Stack stack, int count, [NullValue nullValue]) {
+  List<T?>? pop(Stack stack, int count, [NullValue? nullValue]) {
     if (count == 0) return null;
-    return stack.popList(count, new List<T>.filled(count, null), nullValue);
+    return stack.popList(count, new List<T?>.filled(count, null), nullValue);
   }
 
-  List<T> popPadded(Stack stack, int count, int padding,
-      [NullValue nullValue]) {
+  List<T?>? popPadded(Stack stack, int count, int padding,
+      [NullValue? nullValue]) {
     if (count + padding == 0) return null;
     return stack.popList(
-        count, new List<T>.filled(count + padding, null), nullValue);
+        count, new List<T?>.filled(count + padding, null), nullValue);
   }
 }
 
@@ -670,10 +675,10 @@
 class GrowableList<T> {
   const GrowableList();
 
-  List<T> pop(Stack stack, int count, [NullValue nullValue]) {
+  List<T?>? pop(Stack stack, int count, [NullValue? nullValue]) {
     return stack.popList(
         count,
-        new List<T>.filled(count, /* fill = */ null, growable: true),
+        new List<T?>.filled(count, /* fill = */ null, growable: true),
         nullValue);
   }
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/token_stream_rewriter.dart b/pkg/_fe_analyzer_shared/lib/src/parser/token_stream_rewriter.dart
index 7868ae5..51adec3 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/token_stream_rewriter.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/token_stream_rewriter.dart
@@ -23,7 +23,7 @@
   /// open parenthesis. If [insertIdentifier] is true, then a synthetic
   /// identifier is included between the open and close parenthesis.
   Token insertParens(Token token, bool includeIdentifier) {
-    Token next = token.next;
+    Token next = token.next!;
     int offset = next.charOffset;
     BeginToken leftParen =
         next = new SyntheticBeginToken(TokenType.OPEN_PAREN, offset);
@@ -35,7 +35,7 @@
     }
     next = _setNext(next, new SyntheticToken(TokenType.CLOSE_PAREN, offset));
     _setEndGroup(leftParen, next);
-    _setNext(next, token.next);
+    _setNext(next, token.next!);
 
     // A no-op rewriter could skip this step.
     _setNext(token, leftParen);
@@ -45,7 +45,7 @@
 
   /// Insert [newToken] after [token] and return [newToken].
   Token insertToken(Token token, Token newToken) {
-    _setNext(newToken, token.next);
+    _setNext(newToken, token.next!);
 
     // A no-op rewriter could skip this step.
     _setNext(token, newToken);
@@ -56,18 +56,19 @@
   /// Move [endGroup] (a synthetic `)`, `]`, or `}` token) and associated
   /// error token after [token] in the token stream and return [endGroup].
   Token moveSynthetic(Token token, Token endGroup) {
+    // ignore:unnecessary_null_comparison
     assert(endGroup.beforeSynthetic != null);
     if (token == endGroup) return endGroup;
-    Token errorToken;
+    Token? errorToken;
     if (endGroup.next is UnmatchedToken) {
       errorToken = endGroup.next;
     }
 
     // Remove endGroup from its current location
-    _setNext(endGroup.beforeSynthetic, (errorToken ?? endGroup).next);
+    _setNext(endGroup.beforeSynthetic!, (errorToken ?? endGroup).next!);
 
     // Insert endGroup into its new location
-    Token next = token.next;
+    Token next = token.next!;
     _setNext(token, endGroup);
     _setNext(errorToken ?? endGroup, next);
     _setOffset(endGroup, next.offset);
@@ -82,13 +83,13 @@
   /// the chain of tokens starting at the [replacementToken]. Return the
   /// [replacementToken].
   Token replaceTokenFollowing(Token previousToken, Token replacementToken) {
-    Token replacedToken = previousToken.next;
+    Token replacedToken = previousToken.next!;
     _setNext(previousToken, replacementToken);
 
     _setPrecedingComments(
         replacementToken as SimpleToken, replacedToken.precedingComments);
 
-    _setNext(_lastTokenInChain(replacementToken), replacedToken.next);
+    _setNext(_lastTokenInChain(replacementToken), replacedToken.next!);
 
     return replacementToken;
   }
@@ -99,14 +100,14 @@
   /// As a side-effect, this method also ensures that the tokens in the chain
   /// have their `previous` pointers set correctly.
   Token _lastTokenInChain(Token firstToken) {
-    Token previous;
+    Token? previous;
     Token current = firstToken;
-    while (current.next != null && current.next.type != TokenType.EOF) {
+    while (current.next != null && current.next!.type != TokenType.EOF) {
       if (previous != null) {
         _setPrevious(current, previous);
       }
       previous = current;
-      current = current.next;
+      current = current.next!;
     }
     if (previous != null) {
       _setPrevious(current, previous);
@@ -126,39 +127,39 @@
 
     // [token] <--> [a] <--> [b]
     ReplacementToken replacement =
-        new ReplacementToken(newTokenType, previousToken.next);
+        new ReplacementToken(newTokenType, previousToken.next!);
     insertToken(previousToken, replacement);
     // [token] <--> [replacement] <--> [a] <--> [b]
-    _setNext(replacement, replacement.next.next);
+    _setNext(replacement, replacement.next!.next!);
     // [token] <--> [replacement] <--> [b]
 
     return replacement;
   }
 
   /// Insert a synthetic identifier after [token] and return the new identifier.
-  Token insertSyntheticIdentifier(Token token, [String value]) {
+  Token insertSyntheticIdentifier(Token token, [String value = '']) {
     return insertToken(
         token,
-        new SyntheticStringToken(TokenType.IDENTIFIER, value ?? '',
-            token.next.charOffset, /* _length = */ 0));
+        new SyntheticStringToken(TokenType.IDENTIFIER, value,
+            token.next!.charOffset, /* _length = */ 0));
   }
 
   /// Insert a new synthetic [keyword] after [token] and return the new token.
   Token insertSyntheticKeyword(Token token, Keyword keyword) => insertToken(
-      token, new SyntheticKeywordToken(keyword, token.next.charOffset));
+      token, new SyntheticKeywordToken(keyword, token.next!.charOffset));
 
   /// Insert a new simple synthetic token of [newTokenType] after [token]
   /// and return the new token.
   Token insertSyntheticToken(Token token, TokenType newTokenType) {
     assert(newTokenType is! Keyword, 'use insertSyntheticKeyword instead');
     return insertToken(
-        token, new SyntheticToken(newTokenType, token.next.charOffset));
+        token, new SyntheticToken(newTokenType, token.next!.charOffset));
   }
 
   Token _setNext(Token setOn, Token nextToken);
   void _setEndGroup(BeginToken setOn, Token endGroup);
   void _setOffset(Token setOn, int offset);
-  void _setPrecedingComments(SimpleToken setOn, CommentToken comment);
+  void _setPrecedingComments(SimpleToken setOn, CommentToken? comment);
   void _setPrevious(Token setOn, Token previous);
 }
 
@@ -197,7 +198,7 @@
     setOn.offset = offset;
   }
 
-  void _setPrecedingComments(SimpleToken setOn, CommentToken comment) {
+  void _setPrecedingComments(SimpleToken setOn, CommentToken? comment) {
     setOn.precedingComments = comment;
   }
 
@@ -211,11 +212,11 @@
 }
 
 class NextTokenStreamChange implements TokenStreamChange {
-  Token setOn;
-  Token setOnNext;
-  Token nextToken;
-  Token nextTokenPrevious;
-  Token nextTokenBeforeSynthetic;
+  late Token setOn;
+  Token? setOnNext;
+  late Token nextToken;
+  Token? nextTokenPrevious;
+  Token? nextTokenBeforeSynthetic;
 
   NextTokenStreamChange(UndoableTokenStreamRewriter rewriter) {
     rewriter._changes.add(this);
@@ -244,8 +245,8 @@
 }
 
 class EndGroupTokenStreamChange implements TokenStreamChange {
-  BeginToken setOn;
-  Token endGroup;
+  late BeginToken setOn;
+  Token? endGroup;
 
   EndGroupTokenStreamChange(UndoableTokenStreamRewriter rewriter) {
     rewriter._changes.add(this);
@@ -265,8 +266,8 @@
 }
 
 class OffsetTokenStreamChange implements TokenStreamChange {
-  Token setOn;
-  int offset;
+  late Token setOn;
+  late int offset;
 
   OffsetTokenStreamChange(UndoableTokenStreamRewriter rewriter) {
     rewriter._changes.add(this);
@@ -286,14 +287,14 @@
 }
 
 class PrecedingCommentsTokenStreamChange implements TokenStreamChange {
-  SimpleToken setOn;
-  CommentToken comment;
+  late SimpleToken setOn;
+  CommentToken? comment;
 
   PrecedingCommentsTokenStreamChange(UndoableTokenStreamRewriter rewriter) {
     rewriter._changes.add(this);
   }
 
-  void setPrecedingComments(SimpleToken setOn, CommentToken comment) {
+  void setPrecedingComments(SimpleToken setOn, CommentToken? comment) {
     this.setOn = setOn;
     this.comment = setOn.precedingComments;
 
@@ -307,8 +308,8 @@
 }
 
 class PreviousTokenStreamChange implements TokenStreamChange {
-  Token setOn;
-  Token previous;
+  late Token setOn;
+  late Token previous;
 
   PreviousTokenStreamChange(UndoableTokenStreamRewriter rewriter) {
     rewriter._changes.add(this);
@@ -316,7 +317,7 @@
 
   void setPrevious(Token setOn, Token previous) {
     this.setOn = setOn;
-    this.previous = setOn.previous;
+    this.previous = setOn.previous!;
 
     setOn.previous = previous;
   }
@@ -357,7 +358,7 @@
   }
 
   @override
-  void _setPrecedingComments(SimpleToken setOn, CommentToken comment) {
+  void _setPrecedingComments(SimpleToken setOn, CommentToken? comment) {
     new PrecedingCommentsTokenStreamChange(this)
         .setPrecedingComments(setOn, comment);
   }
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/top_level_parser.dart b/pkg/_fe_analyzer_shared/lib/src/parser/top_level_parser.dart
index b8b39e0..93be64c 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/top_level_parser.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/top_level_parser.dart
@@ -18,7 +18,7 @@
   TopLevelParser(Listener listener) : super(listener);
 
   @override
-  Token parseClassOrMixinOrExtensionBody(
-          Token token, DeclarationKind kind, String enclosingDeclarationName) =>
+  Token parseClassOrMixinOrExtensionBody(Token token, DeclarationKind kind,
+          String? enclosingDeclarationName) =>
       skipClassOrMixinOrExtensionBody(token);
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart b/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
index 260047a..c865e0a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
@@ -117,7 +117,7 @@
 
 bool isGeneralizedFunctionType(Token token) {
   return optional('Function', token) &&
-      (optional('<', token.next) || optional('(', token.next));
+      (optional('<', token.next!) || optional('(', token.next!));
 }
 
 bool isValidTypeReference(Token token) {
@@ -127,7 +127,7 @@
     TokenType type = token.type;
     String value = type.lexeme;
     return type.isPseudo ||
-        (type.isBuiltIn && optional('.', token.next)) ||
+        (type.isBuiltIn && optional('.', token.next!)) ||
         (identical(value, 'dynamic')) ||
         (identical(value, 'void'));
   }
@@ -141,24 +141,24 @@
 /// given unbalanced `<` `>` and invalid parameters or arguments.
 TypeInfo computeType(final Token token, bool required,
     [bool inDeclaration = false]) {
-  Token next = token.next;
+  Token next = token.next!;
   if (!isValidTypeReference(next)) {
     if (next.type.isBuiltIn) {
       TypeParamOrArgInfo typeParamOrArg =
           computeTypeParamOrArg(next, inDeclaration);
       if (typeParamOrArg != noTypeParamOrArg) {
         // Recovery: built-in `<` ... `>`
-        if (required || looksLikeName(typeParamOrArg.skip(next).next)) {
+        if (required || looksLikeName(typeParamOrArg.skip(next).next!)) {
           return new ComplexTypeInfo(token, typeParamOrArg)
               .computeBuiltinOrVarAsType(required);
         }
-      } else if (required || isGeneralizedFunctionType(next.next)) {
-        String value = next.stringValue;
+      } else if (required || isGeneralizedFunctionType(next.next!)) {
+        String? value = next.stringValue;
         if ((!identical('get', value) &&
             !identical('set', value) &&
             !identical('factory', value) &&
             !identical('operator', value) &&
-            !(identical('typedef', value) && next.next.isIdentifier))) {
+            !(identical('typedef', value) && next.next!.isIdentifier))) {
           return new ComplexTypeInfo(token, typeParamOrArg)
               .computeBuiltinOrVarAsType(required);
         }
@@ -171,7 +171,7 @@
                 token, computeTypeParamOrArg(next, inDeclaration))
             .computePrefixedType(required);
       } else if (optional('var', next) &&
-          isOneOf(next.next, const ['<', ',', '>'])) {
+          isOneOf(next.next!, const ['<', ',', '>'])) {
         return new ComplexTypeInfo(
                 token, computeTypeParamOrArg(next, inDeclaration))
             .computeBuiltinOrVarAsType(required);
@@ -181,7 +181,7 @@
   }
 
   if (optional('void', next)) {
-    next = next.next;
+    next = next.next!;
     if (isGeneralizedFunctionType(next)) {
       // `void` `Function` ...
       return new ComplexTypeInfo(token, noTypeParamOrArg)
@@ -204,9 +204,9 @@
   if (typeParamOrArg != noTypeParamOrArg) {
     if (typeParamOrArg.isSimpleTypeArgument) {
       // We've seen identifier `<` identifier `>`
-      next = typeParamOrArg.skip(next).next;
+      next = typeParamOrArg.skip(next).next!;
       if (optional('?', next)) {
-        next = next.next;
+        next = next.next!;
         if (!isGeneralizedFunctionType(next)) {
           if ((required || looksLikeName(next)) &&
               typeParamOrArg == simpleTypeArgument1) {
@@ -235,16 +235,16 @@
   }
 
   assert(typeParamOrArg == noTypeParamOrArg);
-  next = next.next;
+  next = next.next!;
   if (optional('.', next)) {
-    next = next.next;
+    next = next.next!;
     if (isValidTypeReference(next)) {
       // We've seen identifier `.` identifier
       typeParamOrArg = computeTypeParamOrArg(next, inDeclaration);
-      next = next.next;
+      next = next.next!;
       if (typeParamOrArg == noTypeParamOrArg) {
         if (optional('?', next)) {
-          next = next.next;
+          next = next.next!;
           if (!isGeneralizedFunctionType(next)) {
             if (required || looksLikeName(next)) {
               // identifier `.` identifier `?` identifier
@@ -273,7 +273,7 @@
     }
     // identifier `.` non-identifier
     if (required) {
-      typeParamOrArg = computeTypeParamOrArg(token.next.next, inDeclaration);
+      typeParamOrArg = computeTypeParamOrArg(token.next!.next!, inDeclaration);
       return new ComplexTypeInfo(token, typeParamOrArg)
           .computePrefixedType(required);
     }
@@ -288,7 +288,7 @@
   }
 
   if (optional('?', next)) {
-    next = next.next;
+    next = next.next!;
     if (isGeneralizedFunctionType(next)) {
       // identifier `?` Function `(`
       return new ComplexTypeInfo(token, noTypeParamOrArg)
@@ -312,20 +312,20 @@
 /// given unbalanced `<` `>` and invalid parameters or arguments.
 TypeParamOrArgInfo computeTypeParamOrArg(Token token,
     [bool inDeclaration = false, bool allowsVariance = false]) {
-  Token beginGroup = token.next;
+  Token beginGroup = token.next!;
   if (!optional('<', beginGroup)) {
     return noTypeParamOrArg;
   }
 
   // identifier `<` `void` `>` and `<` `dynamic` `>`
   // are handled by ComplexTypeInfo.
-  Token next = beginGroup.next;
+  Token next = beginGroup.next!;
   if ((next.kind == IDENTIFIER_TOKEN || next.type.isPseudo)) {
-    if (optional('>', next.next)) {
+    if (optional('>', next.next!)) {
       return simpleTypeArgument1;
-    } else if (optional('>>', next.next)) {
+    } else if (optional('>>', next.next!)) {
       return simpleTypeArgument1GtGt;
-    } else if (optional('>=', next.next)) {
+    } else if (optional('>=', next.next!)) {
       return simpleTypeArgument1GtEq;
     }
   } else if (optional('(', next)) {
@@ -346,5 +346,5 @@
 /// possible other constructs will pass (e.g., 'a < C, D > 3').
 TypeParamOrArgInfo computeMethodTypeArguments(Token token) {
   TypeParamOrArgInfo typeArg = computeTypeParamOrArg(token);
-  return optional('(', typeArg.skip(token).next) ? typeArg : noTypeParamOrArg;
+  return optional('(', typeArg.skip(token).next!) ? typeArg : noTypeParamOrArg;
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/type_info_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/type_info_impl.dart
index 6e81efc..5df6fee 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/type_info_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/type_info_impl.dart
@@ -107,7 +107,7 @@
   @override
   Token ensureTypeNotVoid(Token token, Parser parser) {
     parser.reportRecoverableErrorWithToken(
-        token.next, codes.templateExpectedType);
+        token.next!, codes.templateExpectedType);
     parser.rewriter.insertSyntheticIdentifier(token);
     return simpleType.parseType(token, parser);
   }
@@ -162,28 +162,28 @@
 
   @override
   Token parseType(Token token, Parser parser) {
-    Token start = token = token.next;
+    Token start = token = token.next!;
     assert(token.isKeywordOrIdentifier);
     Listener listener = parser.listener;
     listener.handleIdentifier(token, IdentifierContext.prefixedTypeReference);
 
-    Token period = token = token.next;
+    Token period = token = token.next!;
     assert(optional('.', token));
 
-    token = token.next;
+    token = token.next!;
     assert(token.isKeywordOrIdentifier);
     listener.handleIdentifier(
         token, IdentifierContext.typeReferenceContinuation);
     listener.handleQualified(period);
 
-    listener.handleNoTypeArguments(token.next);
+    listener.handleNoTypeArguments(token.next!);
     listener.handleType(start, /* questionMark = */ null);
     return token;
   }
 
   @override
   Token skipType(Token token) {
-    return token.next.next.next;
+    return token.next!.next!.next!;
   }
 }
 
@@ -202,7 +202,7 @@
 
   @override
   Token parseTypeRest(Token start, Token token, Parser parser) {
-    token = token.next;
+    token = token.next!;
     assert(optional('?', token));
     parser.listener.handleType(start, token);
     return token;
@@ -210,7 +210,7 @@
 
   @override
   Token skipType(Token token) {
-    token = super.skipType(token).next;
+    token = super.skipType(token).next!;
     assert(optional('?', token));
     return token;
   }
@@ -248,7 +248,7 @@
 
   @override
   Token parseType(Token token, Parser parser) {
-    Token start = token = token.next;
+    Token start = token = token.next!;
     assert(token.isKeywordOrIdentifier);
     parser.listener.handleIdentifier(token, IdentifierContext.typeReference);
     token = typeArg.parseArguments(token, parser);
@@ -262,7 +262,7 @@
 
   @override
   Token skipType(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(token.isKeywordOrIdentifier);
     return typeArg.skip(token);
   }
@@ -283,7 +283,7 @@
 
   @override
   Token parseTypeRest(Token start, Parser parser) {
-    Token token = start.next;
+    Token token = start.next!;
     assert(optional('?', token));
     parser.listener.handleType(start, token);
     return token;
@@ -291,7 +291,7 @@
 
   @override
   Token skipType(Token token) {
-    return token.next.next;
+    return token.next!.next!;
   }
 }
 
@@ -325,7 +325,7 @@
 
   @override
   Token parseType(Token token, Parser parser) {
-    token = token.next;
+    token = token.next!;
     assert(isValidTypeReference(token));
     parser.listener.handleIdentifier(token, IdentifierContext.typeReference);
     token = noTypeParamOrArg.parseArguments(token, parser);
@@ -339,7 +339,7 @@
 
   @override
   Token skipType(Token token) {
-    return token.next;
+    return token.next!;
   }
 }
 
@@ -362,7 +362,7 @@
   @override
   Token ensureTypeNotVoid(Token token, Parser parser) {
     // Report an error, then parse `void` as if it were a type name.
-    parser.reportRecoverableError(token.next, codes.messageInvalidVoid);
+    parser.reportRecoverableError(token.next!, codes.messageInvalidVoid);
     return simpleType.parseTypeNotVoid(token, parser);
   }
 
@@ -376,16 +376,16 @@
 
   @override
   Token parseType(Token token, Parser parser) {
-    Token voidKeyword = token = token.next;
+    Token voidKeyword = token = token.next!;
     bool hasTypeArguments = false;
 
     // Recovery: Skip past, but issue problem, if followed by type arguments.
-    if (optional('<', token.next)) {
+    if (optional('<', token.next!)) {
       TypeParamOrArgInfo typeParam = computeTypeParamOrArg(token);
       if (typeParam != noTypeParamOrArg) {
         hasTypeArguments = true;
         parser.reportRecoverableError(
-            token.next, codes.messageVoidWithTypeArguments);
+            token.next!, codes.messageVoidWithTypeArguments);
         token = typeParam.parseArguments(token, parser);
       }
     }
@@ -400,9 +400,9 @@
 
   @override
   Token skipType(Token token) {
-    token = token.next;
+    token = token.next!;
     // Recovery: Skip past if followed by type arguments.
-    if (optional('<', token.next)) {
+    if (optional('<', token.next!)) {
       TypeParamOrArgInfo typeParam = computeTypeParamOrArg(token);
       if (typeParam != noTypeParamOrArg) {
         token = typeParam.skip(token);
@@ -419,13 +419,13 @@
         // Although `typedef` is a legal identifier,
         // type `typedef` identifier is not legal and in this situation
         // `typedef` is probably a separate declaration.
-        (!optional('typedef', token) || !token.next.isIdentifier));
+        (!optional('typedef', token) || !token.next!.isIdentifier));
 
 /// When missing a comma, determine if the given token looks like it should
 /// be part of a collection of type parameters or arguments.
 bool looksLikeTypeParamOrArg(bool inDeclaration, Token token) {
   if (inDeclaration && token.kind == IDENTIFIER_TOKEN) {
-    Token next = token.next;
+    Token next = token.next!;
     if (next.kind == IDENTIFIER_TOKEN ||
         optional(',', next) ||
         isCloser(next)) {
@@ -447,10 +447,10 @@
   /// The token before the trailing question mark or `null` if either
   /// 1) there is no trailing question mark, or
   /// 2) the trailing question mark is not part of the type reference.
-  Token beforeQuestionMark;
+  Token? beforeQuestionMark;
 
   /// The last token in the type reference.
-  Token end;
+  Token? end;
 
   /// The `Function` tokens before the start of type variables of function types
   /// as seen during analysis.
@@ -458,10 +458,11 @@
 
   /// If the receiver represents a generalized function type then this indicates
   /// whether it has a return type, otherwise this is `null`.
-  bool gftHasReturnType;
+  bool? gftHasReturnType;
 
   ComplexTypeInfo(Token beforeStart, this.typeArguments)
-      : this.start = beforeStart.next {
+      : this.start = beforeStart.next! {
+    // ignore: unnecessary_null_comparison
     assert(typeArguments != null);
   }
 
@@ -500,7 +501,7 @@
 
   @override
   Token parseType(Token token, Parser parser) {
-    assert(identical(token.next, start));
+    assert(identical(token.next!, start));
 
     if (optional('.', start)) {
       // Recovery: Insert missing identifier without sending events
@@ -509,7 +510,7 @@
     }
 
     final List<Token> typeVariableEndGroups = <Token>[];
-    for (Link<Token> t = typeVariableStarters; t.isNotEmpty; t = t.tail) {
+    for (Link<Token> t = typeVariableStarters; t.isNotEmpty; t = t.tail!) {
       parser.listener.beginFunctionType(start);
       typeVariableEndGroups.add(
           computeTypeParamOrArg(t.head, /* inDeclaration = */ true)
@@ -522,12 +523,12 @@
       // generate the full type.
       noType.parseType(token, parser);
     } else {
-      Token typeRefOrPrefix = token.next;
+      Token typeRefOrPrefix = token.next!;
       if (optional('void', typeRefOrPrefix)) {
         token = voidType.parseType(token, parser);
       } else {
         if (!optional('.', typeRefOrPrefix) &&
-            !optional('.', typeRefOrPrefix.next)) {
+            !optional('.', typeRefOrPrefix.next!)) {
           token =
               parser.ensureIdentifier(token, IdentifierContext.typeReference);
         } else {
@@ -543,7 +544,7 @@
         token = typeArguments.parseArguments(token, parser);
 
         // Only consume the `?` if it is part of the complex type
-        Token questionMark = token.next;
+        Token? questionMark = token.next!;
         if (optional('?', questionMark) &&
             (typeVariableEndGroups.isNotEmpty || beforeQuestionMark != null)) {
           token = questionMark;
@@ -556,12 +557,12 @@
     }
 
     int endGroupIndex = typeVariableEndGroups.length - 1;
-    for (Link<Token> t = typeVariableStarters; t.isNotEmpty; t = t.tail) {
-      token = token.next;
+    for (Link<Token> t = typeVariableStarters; t.isNotEmpty; t = t.tail!) {
+      token = token.next!;
       assert(optional('Function', token));
       Token functionToken = token;
 
-      if (optional("<", token.next)) {
+      if (optional("<", token.next!)) {
         // Skip type parameters, they were parsed above.
         token = typeVariableEndGroups[endGroupIndex];
         assert(optional('>', token));
@@ -570,7 +571,7 @@
           token, MemberKind.GeneralizedFunctionType);
 
       // Only consume the `?` if it is part of the complex type
-      Token questionMark = token.next;
+      Token? questionMark = token.next!;
       if (optional('?', questionMark) &&
           (endGroupIndex > 0 || beforeQuestionMark != null)) {
         token = questionMark;
@@ -597,7 +598,7 @@
 
   @override
   Token skipType(Token token) {
-    return end;
+    return end!;
   }
 
   /// Given `Function` non-identifier, compute the type
@@ -618,7 +619,7 @@
   /// and return the receiver or one of the [TypeInfo] constants.
   TypeInfo computeVoidGFT(bool required) {
     assert(optional('void', start));
-    assert(optional('Function', start.next));
+    assert(optional('Function', start.next!));
 
     computeRest(start, required);
     if (gftHasReturnType == null) {
@@ -632,7 +633,7 @@
   /// and return the receiver or one of the [TypeInfo] constants.
   TypeInfo computeIdentifierGFT(bool required) {
     assert(isValidTypeReference(start));
-    assert(optional('Function', start.next));
+    assert(optional('Function', start.next!));
 
     computeRest(start, required);
     if (gftHasReturnType == null) {
@@ -646,8 +647,8 @@
   /// and return the receiver or one of the [TypeInfo] constants.
   TypeInfo computeIdentifierQuestionGFT(bool required) {
     assert(isValidTypeReference(start));
-    assert(optional('?', start.next));
-    assert(optional('Function', start.next.next));
+    assert(optional('?', start.next!));
+    assert(optional('Function', start.next!.next!));
 
     computeRest(start, required);
     if (gftHasReturnType == null) {
@@ -663,7 +664,7 @@
     assert(start.type.isBuiltIn || optional('var', start));
 
     end = typeArguments.skip(start);
-    computeRest(end, required);
+    computeRest(end!, required);
     assert(end != null);
     return this;
   }
@@ -672,13 +673,13 @@
   /// and return the receiver or one of the [TypeInfo] constants.
   TypeInfo computeSimpleWithTypeArguments(bool required) {
     assert(isValidTypeReference(start));
-    assert(optional('<', start.next));
+    assert(optional('<', start.next!));
     assert(typeArguments != noTypeParamOrArg);
 
     end = typeArguments.skip(start);
-    computeRest(end, required);
+    computeRest(end!, required);
 
-    if (!required && !looksLikeName(end.next) && gftHasReturnType == null) {
+    if (!required && !looksLikeName(end!.next!) && gftHasReturnType == null) {
       return noType;
     }
     assert(end != null);
@@ -692,16 +693,16 @@
     Token token = start;
     if (!optional('.', token)) {
       assert(token.isKeywordOrIdentifier);
-      token = token.next;
+      token = token.next!;
     }
     assert(optional('.', token));
-    if (token.next.isKeywordOrIdentifier) {
-      token = token.next;
+    if (token.next!.isKeywordOrIdentifier) {
+      token = token.next!;
     }
 
     end = typeArguments.skip(token);
-    computeRest(end, required);
-    if (!required && !looksLikeName(end.next) && gftHasReturnType == null) {
+    computeRest(end!, required);
+    if (!required && !looksLikeName(end!.next!) && gftHasReturnType == null) {
       return noType;
     }
     assert(end != null);
@@ -709,28 +710,28 @@
   }
 
   void computeRest(Token token, bool required) {
-    if (optional('?', token.next)) {
+    if (optional('?', token.next!)) {
       beforeQuestionMark = token;
-      end = token = token.next;
+      end = token = token.next!;
     }
-    token = token.next;
+    token = token.next!;
     while (optional('Function', token)) {
       Token typeVariableStart = token;
       // TODO(danrubel): Consider caching TypeParamOrArgInfo
       token =
           computeTypeParamOrArg(token, /* inDeclaration = */ true).skip(token);
-      token = token.next;
+      token = token.next!;
       if (!optional('(', token)) {
         break; // Not a function type.
       }
-      token = token.endGroup;
-      if (token == null) {
+      if (token.endGroup == null) {
         break; // Not a function type.
       }
+      token = token.endGroup!;
       if (!required) {
-        Token next = token.next;
+        Token next = token.next!;
         if (optional('?', next)) {
-          next = next.next;
+          next = next.next!;
         }
         if (!(next.isIdentifier || optional('this', next))) {
           break; // `Function` used as the name in a function declaration.
@@ -742,12 +743,12 @@
 
       beforeQuestionMark = null;
       end = token;
-      token = token.next;
+      token = token.next!;
 
       if (optional('?', token)) {
         beforeQuestionMark = end;
         end = token;
-        token = token.next;
+        token = token.next!;
       }
     }
   }
@@ -762,13 +763,13 @@
 
   @override
   Token parseArguments(Token token, Parser parser) {
-    parser.listener.handleNoTypeArguments(token.next);
+    parser.listener.handleNoTypeArguments(token.next!);
     return token;
   }
 
   @override
   Token parseVariables(Token token, Parser parser) {
-    parser.listener.handleNoTypeVariables(token.next);
+    parser.listener.handleNoTypeVariables(token.next!);
     return token;
   }
 
@@ -790,9 +791,9 @@
 
   @override
   Token parseArguments(Token token, Parser parser) {
-    Token beginGroup = token.next;
+    Token beginGroup = token.next!;
     assert(optional('<', beginGroup));
-    Token endGroup = parseEndGroup(beginGroup, beginGroup.next);
+    Token endGroup = parseEndGroup(beginGroup, beginGroup.next!);
     Listener listener = parser.listener;
     listener.beginTypeArguments(beginGroup);
     simpleType.parseType(beginGroup, parser);
@@ -802,9 +803,9 @@
 
   @override
   Token parseVariables(Token token, Parser parser) {
-    Token beginGroup = token.next;
+    Token beginGroup = token.next!;
     assert(optional('<', beginGroup));
-    token = beginGroup.next;
+    token = beginGroup.next!;
     Token endGroup = parseEndGroup(beginGroup, token);
     Listener listener = parser.listener;
     listener.beginTypeVariables(beginGroup);
@@ -825,21 +826,21 @@
 
   @override
   Token skip(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional('<', token));
-    token = token.next;
+    token = token.next!;
     assert(token.isKeywordOrIdentifier);
     return skipEndGroup(token);
   }
 
   Token skipEndGroup(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional('>', token));
     return token;
   }
 
   Token parseEndGroup(Token beginGroup, Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional('>', token));
     return token;
   }
@@ -852,16 +853,16 @@
   TypeInfo get typeInfo => simpleTypeWith1ArgumentGtEq;
 
   Token skipEndGroup(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional('>=', token));
     return splitGtEq(token);
   }
 
   Token parseEndGroup(Token beginGroup, Token beforeEndGroup) {
-    Token endGroup = beforeEndGroup.next;
+    Token endGroup = beforeEndGroup.next!;
     if (!optional('>', endGroup)) {
       endGroup = splitGtEq(endGroup);
-      endGroup.next.setNext(endGroup.next.next);
+      endGroup.next!.setNext(endGroup.next!.next!);
     }
     beforeEndGroup.setNext(endGroup);
     return endGroup;
@@ -875,16 +876,16 @@
   TypeInfo get typeInfo => simpleTypeWith1ArgumentGtGt;
 
   Token skipEndGroup(Token token) {
-    token = token.next;
+    token = token.next!;
     assert(optional('>>', token));
     return splitGtGt(token);
   }
 
   Token parseEndGroup(Token beginGroup, Token beforeEndGroup) {
-    Token endGroup = beforeEndGroup.next;
+    Token endGroup = beforeEndGroup.next!;
     if (!optional('>', endGroup)) {
       endGroup = splitGtGt(endGroup);
-      endGroup.next.setNext(endGroup.next.next);
+      endGroup.next!.setNext(endGroup.next!.next!);
     }
     beforeEndGroup.setNext(endGroup);
     return endGroup;
@@ -905,20 +906,22 @@
   final bool allowsVariance;
 
   @override
-  int typeArgumentCount;
+  late int typeArgumentCount;
 
   /// The `>` token which ends the type parameter or argument.
   /// This closer may be synthetic, points to the next token in the stream,
   /// is only used when skipping over the type parameters or arguments,
   /// and may not be part of the token stream.
-  Token skipEnd;
+  Token? skipEnd;
 
   ComplexTypeParamOrArgInfo(
       Token token, this.inDeclaration, this.allowsVariance)
-      : assert(optional('<', token.next)),
+      : assert(optional('<', token.next!)),
+        // ignore: unnecessary_null_comparison
         assert(inDeclaration != null),
+        // ignore: unnecessary_null_comparison
         assert(allowsVariance != null),
-        start = token.next;
+        start = token.next!;
 
   /// Parse the tokens and return the receiver or [noTypeParamOrArg] if there
   /// are no type parameters or arguments. This does not modify the token
@@ -931,30 +934,30 @@
       TypeInfo typeInfo =
           computeType(next, /* required = */ true, inDeclaration);
       if (typeInfo == noType) {
-        while (typeInfo == noType && optional('@', next.next)) {
+        while (typeInfo == noType && optional('@', next.next!)) {
           next = skipMetadata(next);
           typeInfo = computeType(next, /* required = */ true, inDeclaration);
         }
         if (typeInfo == noType) {
-          if (next == start && !inDeclaration && !isCloser(next.next)) {
+          if (next == start && !inDeclaration && !isCloser(next.next!)) {
             return noTypeParamOrArg;
           }
-          if (!optional(',', next.next)) {
+          if (!optional(',', next.next!)) {
             token = next;
-            next = token.next;
+            next = token.next!;
             break;
           }
         }
-        assert(typeInfo != noType || optional(',', next.next));
+        assert(typeInfo != noType || optional(',', next.next!));
         // Fall through to process type (if any) and consume `,`
       }
       ++typeArgumentCount;
       token = typeInfo.skipType(next);
-      next = token.next;
+      next = token.next!;
       if (optional('extends', next)) {
         token = computeType(next, /* required = */ true, inDeclaration)
             .skipType(next);
-        next = token.next;
+        next = token.next!;
       }
       if (!optional(',', next)) {
         skipEnd = splitCloser(next);
@@ -978,12 +981,12 @@
     skipEnd = splitCloser(next);
     if (skipEnd == null) {
       if (optional('(', next)) {
-        token = next.endGroup;
-        next = token.next;
+        token = next.endGroup!;
+        next = token.next!;
       }
       skipEnd = splitCloser(next);
       if (skipEnd == null) {
-        skipEnd = splitCloser(next.next);
+        skipEnd = splitCloser(next.next!);
       }
       if (skipEnd == null) {
         skipEnd = syntheticGt(next);
@@ -994,7 +997,7 @@
 
   @override
   Token parseArguments(Token token, Parser parser) {
-    assert(identical(token.next, start));
+    assert(identical(token.next!, start));
     Token next = start;
     parser.listener.beginTypeArguments(start);
     int count = 0;
@@ -1003,8 +1006,8 @@
           computeType(next, /* required = */ true, inDeclaration);
       if (typeInfo == noType) {
         // Recovery
-        while (typeInfo == noType && optional('@', next.next)) {
-          Token atToken = next.next;
+        while (typeInfo == noType && optional('@', next.next!)) {
+          Token atToken = next.next!;
           next = skipMetadata(next);
           parser.reportRecoverableErrorWithEnd(
               atToken, next, codes.messageAnnotationOnTypeArgument);
@@ -1013,7 +1016,7 @@
         // Fall through to process type (if any) and consume `,`
       }
       token = typeInfo.ensureTypeOrVoid(next, parser);
-      next = token.next;
+      next = token.next!;
       ++count;
       if (!optional(',', next)) {
         if (parseCloser(token)) {
@@ -1029,28 +1032,28 @@
         next = parseMissingComma(token, parser);
       }
     }
-    Token endGroup = token.next;
+    Token endGroup = token.next!;
     parser.listener.endTypeArguments(count, start, endGroup);
     return endGroup;
   }
 
   @override
   Token parseVariables(Token token, Parser parser) {
-    assert(identical(token.next, start));
+    assert(identical(token.next!, start));
     Token next = start;
     Listener listener = parser.listener;
     listener.beginTypeVariables(start);
     int count = 0;
 
     Link<Token> typeStarts = const Link<Token>();
-    Link<TypeInfo> superTypeInfos = const Link<TypeInfo>();
-    Link<Token> variances = const Link<Token>();
+    Link<TypeInfo?> superTypeInfos = const Link<TypeInfo?>();
+    Link<Token?> variances = const Link<Token?>();
 
     while (true) {
       token = parser.parseMetadataStar(next);
 
-      Token variance = next.next;
-      Token identifier = variance.next;
+      Token variance = next.next!;
+      Token? identifier = variance.next;
       if (allowsVariance &&
           isVariance(variance) &&
           identifier != null &&
@@ -1058,14 +1061,15 @@
         variances = variances.prepend(variance);
 
         // Recovery for multiple variance modifiers
-        while (isVariance(identifier) &&
+        while (identifier != null &&
+            isVariance(identifier) &&
             identifier.next != null &&
-            identifier.next.isKeywordOrIdentifier) {
+            identifier.next!.isKeywordOrIdentifier) {
           // Report an error and skip actual identifier
           parser.reportRecoverableError(
               identifier, codes.messageMultipleVarianceModifiers);
-          variance = variance.next;
-          identifier = identifier.next;
+          variance = variance.next!;
+          identifier = identifier.next!;
         }
 
         token = variance;
@@ -1079,12 +1083,12 @@
       listener.beginTypeVariable(token);
       typeStarts = typeStarts.prepend(token);
 
-      next = token.next;
+      next = token.next!;
       if (optional('extends', next)) {
         TypeInfo typeInfo =
             computeType(next, /* required = */ true, inDeclaration);
         token = typeInfo.skipType(next);
-        next = token.next;
+        next = token.next!;
         superTypeInfos = superTypeInfos.prepend(typeInfo);
       } else {
         superTypeInfos = superTypeInfos.prepend(/* element = */ null);
@@ -1111,43 +1115,43 @@
     assert(variances.slowLength() == count);
     listener.handleTypeVariablesDefined(token, count);
 
-    token = null;
+    Token? token3 = null;
     while (typeStarts.isNotEmpty) {
       Token token2 = typeStarts.head;
-      TypeInfo typeInfo = superTypeInfos.head;
-      Token variance = variances.head;
+      TypeInfo? typeInfo = superTypeInfos.head;
+      Token? variance = variances.head;
 
-      Token extendsOrSuper = null;
-      Token next2 = token2.next;
+      Token? extendsOrSuper = null;
+      Token next2 = token2.next!;
       if (typeInfo != null) {
         assert(optional('extends', next2));
         extendsOrSuper = next2;
         token2 = typeInfo.ensureTypeNotVoid(next2, parser);
-        next2 = token2.next;
+        next2 = token2.next!;
       } else {
         assert(!optional('extends', next2));
         listener.handleNoType(token2);
       }
       // Type variables are "completed" in reverse order, so capture the last
       // consumed token from the first "completed" type variable.
-      token ??= token2;
+      token3 ??= token2;
       listener.endTypeVariable(next2, --count, extendsOrSuper, variance);
 
-      typeStarts = typeStarts.tail;
-      superTypeInfos = superTypeInfos.tail;
-      variances = variances.tail;
+      typeStarts = typeStarts.tail!;
+      superTypeInfos = superTypeInfos.tail!;
+      variances = variances.tail!;
     }
 
-    if (!parseCloser(token)) {
-      token = parseUnexpectedEnd(token, /* isArguments = */ false, parser);
+    if (!parseCloser(token3!)) {
+      token3 = parseUnexpectedEnd(token3, /* isArguments = */ false, parser);
     }
-    Token endGroup = token.next;
+    Token endGroup = token3.next!;
     listener.endTypeVariables(start, endGroup);
     return endGroup;
   }
 
   Token parseMissingComma(Token token, Parser parser) {
-    Token next = token.next;
+    Token next = token.next!;
     parser.reportRecoverableError(
         next, codes.templateExpectedButGot.withArguments(','));
     return parser.rewriter.insertToken(
@@ -1155,7 +1159,7 @@
   }
 
   Token parseUnexpectedEnd(Token token, bool isArguments, Parser parser) {
-    Token next = token.next;
+    Token next = token.next!;
     bool errorReported = token.isSynthetic || (next.isSynthetic && !next.isEof);
 
     bool typeFollowsExtends = false;
@@ -1166,7 +1170,7 @@
         errorReported = true;
       }
       token = next;
-      next = token.next;
+      next = token.next!;
       typeFollowsExtends = isValidTypeReference(next);
 
       if (parseCloser(token)) {
@@ -1191,7 +1195,7 @@
         final Listener originalListener = parser.listener;
         parser.listener = new ForwardingListener();
         token = invalidType.parseType(token, parser);
-        next = token.next;
+        next = token.next!;
         parser.listener = originalListener;
 
         if (parseCloser(token)) {
@@ -1216,7 +1220,7 @@
       token = isArguments
           ? invalidTypeVar.parseArguments(token, parser)
           : invalidTypeVar.parseVariables(token, parser);
-      next = token.next;
+      next = token.next!;
       parser.listener = originalListener;
 
       if (parseCloser(token)) {
@@ -1231,8 +1235,8 @@
             token, codes.templateExpectedAfterButGot.withArguments('>'));
         errorReported = true;
       }
-      token = next.endGroup;
-      next = token.next;
+      token = next.endGroup!;
+      next = token.next!;
 
       if (parseCloser(token)) {
         return token;
@@ -1247,10 +1251,10 @@
     if (parseCloser(next)) {
       return next;
     }
-    Token endGroup = start.endGroup;
+    Token? endGroup = start.endGroup;
     if (endGroup != null) {
       while (token.next != endGroup && !token.isEof) {
-        token = token.next;
+        token = token.next!;
       }
     } else {
       endGroup = syntheticGt(next);
@@ -1263,7 +1267,7 @@
   @override
   Token skip(Token token) {
     assert(skipEnd != null);
-    return skipEnd;
+    return skipEnd!;
   }
 }
 
@@ -1276,7 +1280,7 @@
 
 /// Return `true` if [token] is one of `>`, `>>`, `>>>`, `>=`, `>>=`, or `>>>=`.
 bool isCloser(Token token) {
-  final String value = token.stringValue;
+  final String? value = token.stringValue;
   return identical(value, '>') ||
       identical(value, '>>') ||
       identical(value, '>=') ||
@@ -1288,14 +1292,14 @@
 /// If [beforeCloser].next is one of `>`, `>>`, `>>>`, `>=`, `>>=`, or `>>>=`
 /// then update the token stream and return `true`.
 bool parseCloser(Token beforeCloser) {
-  Token unsplit = beforeCloser.next;
-  Token split = splitCloser(unsplit);
+  Token unsplit = beforeCloser.next!;
+  Token? split = splitCloser(unsplit);
   if (split == unsplit) {
     return true;
   } else if (split == null) {
     return false;
   }
-  split.next.setNext(unsplit.next);
+  split.next!.setNext(unsplit.next!);
   beforeCloser.setNext(split);
   return true;
 }
@@ -1304,8 +1308,8 @@
 /// If [closer] is one of `>>`, `>>>`, `>=`, `>>=`,  or `>>>=` then split
 /// the token and return the leading `>` without updating the token stream.
 /// If [closer] is none of the above, then return null;
-Token splitCloser(Token closer) {
-  String value = closer.stringValue;
+Token? splitCloser(Token closer) {
+  String? value = closer.stringValue;
   if (identical(value, '>')) {
     return closer;
   } else if (identical(value, '>>')) {
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/util.dart b/pkg/_fe_analyzer_shared/lib/src/parser/util.dart
index dfe02c8..f6f1939 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/util.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/util.dart
@@ -18,16 +18,16 @@
 
 /// Returns the token before the close brace, bracket, or parenthesis
 /// associated with [left]. For '<', it may return `null`.
-Token beforeCloseBraceTokenFor(BeginToken left) {
-  Token endToken = left.endToken;
+Token? beforeCloseBraceTokenFor(BeginToken left) {
+  Token? endToken = left.endToken;
   if (endToken == null) {
     return null;
   }
   Token token = left;
-  Token next = token.next;
+  Token next = token.next!;
   while (next != endToken && next != next.next) {
     token = next;
-    next = token.next;
+    next = token.next!;
   }
   return token;
 }
@@ -36,7 +36,7 @@
 /// not synthetic or synthetic with non-zero length.
 Token findPreviousNonZeroLengthToken(Token token) {
   while (token.isSynthetic && token.length == 0) {
-    Token previous = token.beforeSynthetic;
+    Token? previous = token.beforeSynthetic;
     if (previous == token) {
       throw new StateError("token == token.beforeSynthetic");
     }
@@ -53,7 +53,7 @@
 /// This may return EOF if there are no more non-synthetic tokens in the stream.
 Token findNonZeroLengthToken(Token token) {
   while (token.isSynthetic && token.length == 0 && !token.isEof) {
-    token = token.next;
+    token = token.next!;
   }
   return token;
 }
@@ -88,37 +88,37 @@
 
 /// A null-aware alternative to `token.length`.  If [token] is `null`, returns
 /// [noLength].
-int lengthForToken(Token token) {
+int lengthForToken(Token? token) {
   return token == null ? noLength : token.length;
 }
 
 /// Returns the length of the span from [begin] to [end] (inclusive). If both
 /// tokens are null, return [noLength]. If one of the tokens are null, return
 /// the length of the other token.
-int lengthOfSpan(Token begin, Token end) {
+int lengthOfSpan(Token? begin, Token? end) {
   if (begin == null) return lengthForToken(end);
   if (end == null) return lengthForToken(begin);
   return end.offset + end.length - begin.offset;
 }
 
 Token skipMetadata(Token token) {
-  token = token.next;
+  token = token.next!;
   assert(optional('@', token));
-  Token next = token.next;
+  Token next = token.next!;
   if (next.isIdentifier) {
     token = next;
-    next = token.next;
+    next = token.next!;
     while (optional('.', next)) {
       token = next;
-      next = token.next;
+      next = token.next!;
       if (next.isIdentifier) {
         token = next;
-        next = token.next;
+        next = token.next!;
       }
     }
-    if (optional('(', next) && !next.endGroup.isSynthetic) {
-      token = next.endGroup;
-      next = token.next;
+    if (optional('(', next) && !next.endGroup!.isSynthetic) {
+      token = next.endGroup!;
+      next = token.next!;
     }
   }
   return token;
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/value_kind.dart b/pkg/_fe_analyzer_shared/lib/src/parser/value_kind.dart
index 92549f0..ae85d25 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/value_kind.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/value_kind.dart
@@ -13,18 +13,18 @@
   const ValueKind();
 
   /// Checks the [value] an returns `true` if the value is of the expected kind.
-  bool check(Object value);
+  bool check(Object ?value);
 }
 
 /// A [ValueKind] for a particular type [T], optionally with a recognized
 /// [NullValue].
 class SingleValueKind<T> implements ValueKind {
-  final NullValue nullValue;
+  final NullValue? nullValue;
 
   const SingleValueKind([this.nullValue]);
 
   @override
-  bool check(Object value) {
+  bool check(Object? value) {
     if (nullValue != null && value == nullValue) {
       return true;
     }
@@ -46,7 +46,7 @@
   const UnionValueKind(this.kinds);
 
   @override
-  bool check(Object value) {
+  bool check(Object? value) {
     for (ValueKind kind in kinds) {
       if (kind.check(value)) {
         return true;
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
index da4fc35..725cce1 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
@@ -59,7 +59,7 @@
   /// Called when the scanner detects a language version comment
   /// so that the listener can update the scanner configuration
   /// based upon the specified language version.
-  final LanguageVersionChanged languageVersionChanged;
+  final LanguageVersionChanged? languageVersionChanged;
 
   /// Experimental flag for enabling scanning of the `extension` token.
   bool _enableExtensionMethods = false;
@@ -94,12 +94,12 @@
   /**
    * A pointer to the last scanned token.
    */
-  Token tail;
+  late Token tail;
 
   /**
    * A pointer to the last prepended error token.
    */
-  Token errorTail;
+  late Token errorTail;
 
   bool hasErrors = false;
 
@@ -108,14 +108,14 @@
    * before they are assigned to the [Token] precedingComments field
    * of a non-comment token. A value of `null` indicates no comment tokens.
    */
-  CommentToken comments;
+  CommentToken? comments;
 
   /**
    * A pointer to the last scanned comment token or `null` if none.
    */
-  Token commentsTail;
+  Token? commentsTail;
 
-  final List<int> lineStarts;
+  late final List<int> lineStarts;
 
   /**
    * The stack of open groups, e.g [: { ... ( .. :]
@@ -127,9 +127,9 @@
   final bool inRecoveryOption;
   int recoveryCount = 0;
 
-  AbstractScanner(ScannerConfiguration config, this.includeComments,
+  AbstractScanner(ScannerConfiguration? config, this.includeComments,
       this.languageVersionChanged,
-      {int numberOfBytesHint})
+      {int? numberOfBytesHint})
       : lineStarts = new LineStarts(numberOfBytesHint),
         inRecoveryOption = false {
     this.tail = this.tokens;
@@ -154,7 +154,7 @@
   }
 
   @override
-  set configuration(ScannerConfiguration config) {
+  set configuration(ScannerConfiguration? config) {
     if (config != null) {
       _enableExtensionMethods = config.enableExtensionMethods;
       _enableNonNullable = config.enableNonNullable;
@@ -228,7 +228,7 @@
   /**
    * Returns the first token scanned by this [Scanner].
    */
-  Token firstToken() => tokens.next;
+  Token firstToken() => tokens.next!;
 
   /**
    * Notifies that a new token starts at current offset.
@@ -331,7 +331,7 @@
     discardOpenLt();
     while (!groupingStack.isEmpty) {
       unmatchedBeginGroup(groupingStack.head);
-      groupingStack = groupingStack.tail;
+      groupingStack = groupingStack.tail!;
     }
     appendToken(new Token.eof(tokenStart, comments));
   }
@@ -364,7 +364,7 @@
    * Group begin tokens are '{', '(', '[', '<' and '${'.
    */
   void appendBeginGroup(TokenType type) {
-    Token token = new BeginToken(type, tokenStart, comments);
+    BeginToken token = new BeginToken(type, tokenStart, comments);
     appendToken(token);
 
     // { [ ${ cannot appear inside a type parameters / arguments.
@@ -406,13 +406,13 @@
           openKind == OPEN_CURLY_BRACKET_TOKEN);
       // We're ending an interpolated expression.
       begin.endGroup = close;
-      groupingStack = groupingStack.tail;
+      groupingStack = groupingStack.tail!;
       // Using "start-of-text" to signal that we're back in string
       // scanning mode.
       return $STX;
     }
     begin.endGroup = close;
-    groupingStack = groupingStack.tail;
+    groupingStack = groupingStack.tail!;
     return advance();
   }
 
@@ -426,7 +426,7 @@
     if (groupingStack.isEmpty) return;
     if (identical(groupingStack.head.kind, LT_TOKEN)) {
       groupingStack.head.endGroup = tail;
-      groupingStack = groupingStack.tail;
+      groupingStack = groupingStack.tail!;
     }
   }
 
@@ -441,12 +441,12 @@
     if (identical(groupingStack.head.kind, LT_TOKEN)) {
       // Don't assign endGroup: in "T<U<V>>", the '>>' token closes the outer
       // '<', the inner '<' is left without endGroup.
-      groupingStack = groupingStack.tail;
+      groupingStack = groupingStack.tail!;
     }
     if (groupingStack.isEmpty) return;
     if (identical(groupingStack.head.kind, LT_TOKEN)) {
       groupingStack.head.endGroup = tail;
-      groupingStack = groupingStack.tail;
+      groupingStack = groupingStack.tail!;
     }
   }
 
@@ -458,10 +458,10 @@
       errorTail = tail;
     } else {
       token.next = errorTail.next;
-      token.next.previous = token;
+      token.next!.previous = token;
       errorTail.next = token;
       token.previous = errorTail;
-      errorTail = errorTail.next;
+      errorTail = errorTail.next!;
     }
   }
 
@@ -523,7 +523,7 @@
         break; // recover
       }
       first = false;
-      groupingStack = groupingStack.tail;
+      groupingStack = groupingStack.tail!;
     } while (!groupingStack.isEmpty);
 
     recoveryCount++;
@@ -591,7 +591,7 @@
       // The option-runs might have set invalid endGroup pointers. Reset them.
       for (Link<BeginToken> link = originalStack;
           link.isNotEmpty;
-          link = link.tail) {
+          link = link.tail!) {
         link.head.endToken = null;
       }
 
@@ -618,7 +618,7 @@
       if (!identical(entryToUse.head.kind, LT_TOKEN)) {
         unmatchedBeginGroup(originalStack.head);
       }
-      originalStack = originalStack.tail;
+      originalStack = originalStack.tail!;
     }
   }
 
@@ -636,7 +636,7 @@
   void discardOpenLt() {
     while (!groupingStack.isEmpty &&
         identical(groupingStack.head.kind, LT_TOKEN)) {
-      groupingStack = groupingStack.tail;
+      groupingStack = groupingStack.tail!;
     }
   }
 
@@ -650,7 +650,7 @@
     while (!groupingStack.isEmpty) {
       BeginToken beginToken = groupingStack.head;
       unmatchedBeginGroup(beginToken);
-      groupingStack = groupingStack.tail;
+      groupingStack = groupingStack.tail!;
       if (identical(beginToken.kind, STRING_INTERPOLATION_TOKEN)) break;
     }
   }
@@ -1432,7 +1432,7 @@
         createLanguageVersionToken(start, major, minor);
     if (languageVersionChanged != null) {
       // TODO(danrubel): make this required and remove the languageVersion field
-      languageVersionChanged(this, languageVersion);
+      languageVersionChanged!(this, languageVersion);
     } else {
       // TODO(danrubel): remove this hack and require listener to update
       // the scanner's configuration.
@@ -1536,7 +1536,7 @@
 
   void appendDartDoc(int start, TokenType type, bool asciiOnly) {
     if (!includeComments) return;
-    Token newComment = createDartDocToken(type, start, asciiOnly);
+    CommentToken newComment = createDartDocToken(type, start, asciiOnly);
     _appendToCommentStream(newComment);
   }
 
@@ -1557,14 +1557,14 @@
     }
   }
 
-  void _appendToCommentStream(Token newComment) {
+  void _appendToCommentStream(CommentToken newComment) {
     if (comments == null) {
       comments = newComment;
       commentsTail = comments;
     } else {
-      commentsTail.next = newComment;
-      commentsTail.next.previous = commentsTail;
-      commentsTail = commentsTail.next;
+      commentsTail!.next = newComment;
+      commentsTail!.next!.previous = commentsTail;
+      commentsTail = commentsTail!.next;
     }
   }
 
@@ -1580,7 +1580,7 @@
   }
 
   int tokenizeKeywordOrIdentifier(int next, bool allowDollar) {
-    KeywordState state = KeywordState.KEYWORD_STATE;
+    KeywordState? state = KeywordState.KEYWORD_STATE;
     int start = scanOffset;
     // We allow a leading capital character.
     if ($A <= next && next <= $Z) {
@@ -1596,14 +1596,18 @@
       state = state.next(next);
       next = advance();
     }
-    if (state == null || state.keyword == null) {
+    if (state == null) {
       return tokenizeIdentifier(next, start, allowDollar);
     }
-    if (!_enableExtensionMethods && state.keyword == Keyword.EXTENSION) {
+    Keyword? keyword = state.keyword;
+    if (keyword == null) {
+      return tokenizeIdentifier(next, start, allowDollar);
+    }
+    if (!_enableExtensionMethods && keyword == Keyword.EXTENSION) {
       return tokenizeIdentifier(next, start, allowDollar);
     }
     if (!_enableNonNullable &&
-        (state.keyword == Keyword.LATE || state.keyword == Keyword.REQUIRED)) {
+        (keyword == Keyword.LATE || keyword == Keyword.REQUIRED)) {
       return tokenizeIdentifier(next, start, allowDollar);
     }
     if (($A <= next && next <= $Z) ||
@@ -1612,7 +1616,7 @@
         identical(next, $$)) {
       return tokenizeIdentifier(next, start, allowDollar);
     } else {
-      appendKeywordToken(state.keyword);
+      appendKeywordToken(keyword);
       return next;
     }
   }
@@ -1883,7 +1887,7 @@
       if (tail.type == TokenType.IDENTIFIER && tail.charEnd == tokenStart) {
         charOffset = tail.charOffset;
         codeUnits.addAll(tail.lexeme.codeUnits);
-        tail = tail.previous;
+        tail = tail.previous!;
       } else {
         charOffset = errorToken.charOffset;
       }
@@ -1910,7 +1914,9 @@
   }
 
   void unterminatedString(int quoteChar, int quoteStart, int start,
-      {bool asciiOnly, bool isMultiLine, bool isRaw}) {
+      {required bool asciiOnly,
+      required bool isMultiLine,
+      required bool isRaw}) {
     String suffix = new String.fromCharCodes(
         isMultiLine ? [quoteChar, quoteChar, quoteChar] : [quoteChar]);
     String prefix = isRaw ? 'r$suffix' : suffix;
@@ -1938,14 +1944,14 @@
     '{': TokenType.CLOSE_CURLY_BRACKET,
     '<': TokenType.GT,
     r'${': TokenType.CLOSE_CURLY_BRACKET,
-  }[begin.lexeme];
+  }[begin.lexeme]!;
 }
 
 class LineStarts extends Object with ListMixin<int> {
-  List<int> array;
+  late List<int> array;
   int arrayLength = 0;
 
-  LineStarts(int numberOfBytesHint) {
+  LineStarts(int? numberOfBytesHint) {
     // Let's assume the average Dart file is 300 bytes.
     if (numberOfBytesHint == null) numberOfBytesHint = 300;
 
@@ -2038,12 +2044,12 @@
   final bool enableTripleShift;
 
   const ScannerConfiguration({
-    bool enableExtensionMethods,
-    bool enableNonNullable,
-    bool enableTripleShift,
-  })  : this.enableExtensionMethods = enableExtensionMethods ?? false,
-        this.enableNonNullable = enableNonNullable ?? false,
-        this.enableTripleShift = enableTripleShift ?? false;
+    bool enableExtensionMethods = false,
+    bool enableNonNullable = false,
+    bool enableTripleShift = false,
+  })  : this.enableExtensionMethods = enableExtensionMethods,
+        this.enableNonNullable = enableNonNullable,
+        this.enableTripleShift = enableTripleShift;
 }
 
 bool _isIdentifierChar(int next, bool allowDollar) {
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/error_token.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/error_token.dart
index f7d9d66..9b39e96 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/error_token.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/error_token.dart
@@ -94,13 +94,13 @@
 
   Code<dynamic> get errorCode => assertionMessage.code;
 
-  int get character => null;
+  int? get character => null;
 
-  String get start => null;
+  String? get start => null;
 
-  int get endOffset => null;
+  int? get endOffset => null;
 
-  BeginToken get begin => null;
+  BeginToken? get begin => null;
 
   @override
   Token copy() {
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/errors.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/errors.dart
index 5e87329..a5c83a9 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/errors.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/errors.dart
@@ -16,7 +16,7 @@
   int charOffset = token.charOffset;
   // TODO(paulberry,ahe): why is endOffset sometimes null?
   int endOffset = token.endOffset ?? charOffset;
-  void _makeError(ScannerErrorCode errorCode, List<Object> arguments) {
+  void _makeError(ScannerErrorCode errorCode, List<Object?>? arguments) {
     if (_isAtEnd(token, charOffset)) {
       // Analyzer never generates an error message past the end of the input,
       // since such an error would not be visible in an editor.
@@ -64,8 +64,8 @@
 
     default:
       if (errorCode == codeUnmatchedToken) {
-        charOffset = token.begin.endToken.charOffset;
-        TokenType type = token.begin?.type;
+        charOffset = token.begin!.endToken!.charOffset;
+        TokenType type = token.begin!.type;
         if (type == TokenType.OPEN_CURLY_BRACKET ||
             type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
           return _makeError(ScannerErrorCode.EXPECTED_TOKEN, ['}']);
@@ -94,7 +94,7 @@
 bool _isAtEnd(Token token, int charOffset) {
   while (true) {
     // Skip to the next token.
-    token = token.next;
+    token = token.next!;
     // If we've found an EOF token, its charOffset indicates where the end of
     // the input is.
     if (token.isEof) return token.charOffset == charOffset;
@@ -111,7 +111,7 @@
  * The [arguments] are any arguments needed to complete the error message.
  */
 typedef ReportError(
-    ScannerErrorCode errorCode, int offset, List<Object> arguments);
+    ScannerErrorCode errorCode, int offset, List<Object?>? arguments);
 
 /**
  * The error codes used for errors detected by the scanner.
@@ -181,7 +181,7 @@
    * template. The correction associated with the error will be created from the
    * given [correction] template.
    */
-  const ScannerErrorCode(String name, String message, {String correction})
+  const ScannerErrorCode(String name, String message, {String? correction})
       : super(
           correction: correction,
           message: message,
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/keyword_state.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/keyword_state.dart
index 05f07e0..51a9520 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/keyword_state.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/keyword_state.dart
@@ -12,19 +12,17 @@
  * Abstract state in a state machine for scanning keywords.
  */
 abstract class KeywordState {
-  KeywordState next(int c);
-  KeywordState nextCapital(int c);
+  KeywordState? next(int c);
+  KeywordState? nextCapital(int c);
 
-  analyzer.Keyword get keyword;
+  analyzer.Keyword? get keyword;
 
-  static KeywordState _KEYWORD_STATE;
+  static KeywordState? _KEYWORD_STATE;
   static KeywordState get KEYWORD_STATE {
     if (_KEYWORD_STATE == null) {
-      List<String> strings =
-          new List<String>.filled(analyzer.Keyword.values.length, null);
-      for (int i = 0; i < analyzer.Keyword.values.length; i++) {
-        strings[i] = analyzer.Keyword.values[i].lexeme;
-      }
+      List<String> strings = analyzer.Keyword.values
+          .map((keyword) => keyword.lexeme)
+          .toList(growable: false);
       strings.sort((a, b) => a.compareTo(b));
       _KEYWORD_STATE = computeKeywordStateTable(
           /* start = */ 0,
@@ -32,14 +30,15 @@
           /* offset = */ 0,
           strings.length);
     }
-    return _KEYWORD_STATE;
+    return _KEYWORD_STATE!;
   }
 
   static KeywordState computeKeywordStateTable(
       int start, List<String> strings, int offset, int length) {
     bool isLowercase = true;
 
-    List<KeywordState> table = new List<KeywordState>.filled($z - $A + 1, null);
+    List<KeywordState?> table =
+        new List<KeywordState?>.filled($z - $A + 1, null);
     assert(length != 0);
     int chunk = 0;
     int chunkStart = -1;
@@ -72,7 +71,7 @@
       assert(length == 1);
       return new LeafKeywordState(strings[offset]);
     }
-    String syntax = isLeaf ? strings[offset] : null;
+    String? syntax = isLeaf ? strings[offset] : null;
     if (isLowercase) {
       table = table.sublist($a - $A);
       return new LowerCaseArrayKeywordState(table, syntax);
@@ -86,15 +85,15 @@
  * A state with multiple outgoing transitions.
  */
 abstract class ArrayKeywordState implements KeywordState {
-  final List<KeywordState> table;
-  final analyzer.Keyword keyword;
+  final List<KeywordState?> table;
+  final analyzer.Keyword? keyword;
 
-  ArrayKeywordState(this.table, String syntax)
+  ArrayKeywordState(this.table, String? syntax)
       : keyword = ((syntax == null) ? null : analyzer.Keyword.keywords[syntax]);
 
-  KeywordState next(int c);
+  KeywordState? next(int c);
 
-  KeywordState nextCapital(int c);
+  KeywordState? nextCapital(int c);
 
   String toString() {
     StringBuffer sb = new StringBuffer();
@@ -104,7 +103,7 @@
       sb.write(keyword);
       sb.write(" ");
     }
-    List<KeywordState> foo = table;
+    List<KeywordState?> foo = table;
     for (int i = 0; i < foo.length; i++) {
       if (foo[i] != null) {
         sb.write("${new String.fromCharCodes([i + $a])}: "
@@ -117,25 +116,25 @@
 }
 
 class LowerCaseArrayKeywordState extends ArrayKeywordState {
-  LowerCaseArrayKeywordState(List<KeywordState> table, String syntax)
+  LowerCaseArrayKeywordState(List<KeywordState?> table, String? syntax)
       : super(table, syntax) {
     assert(table.length == $z - $a + 1);
   }
 
-  KeywordState next(int c) => table[c - $a];
+  KeywordState? next(int c) => table[c - $a];
 
-  KeywordState nextCapital(int c) => null;
+  KeywordState? nextCapital(int c) => null;
 }
 
 class UpperCaseArrayKeywordState extends ArrayKeywordState {
-  UpperCaseArrayKeywordState(List<KeywordState> table, String syntax)
+  UpperCaseArrayKeywordState(List<KeywordState?> table, String? syntax)
       : super(table, syntax) {
     assert(table.length == $z - $A + 1);
   }
 
-  KeywordState next(int c) => table[c - $A];
+  KeywordState? next(int c) => table[c - $A];
 
-  KeywordState nextCapital(int c) => table[c - $A];
+  KeywordState? nextCapital(int c) => table[c - $A];
 }
 
 /**
@@ -144,10 +143,11 @@
 class LeafKeywordState implements KeywordState {
   final analyzer.Keyword keyword;
 
-  LeafKeywordState(String syntax) : keyword = analyzer.Keyword.keywords[syntax];
+  LeafKeywordState(String syntax)
+      : keyword = analyzer.Keyword.keywords[syntax]!;
 
-  KeywordState next(int c) => null;
-  KeywordState nextCapital(int c) => null;
+  KeywordState? next(int c) => null;
+  KeywordState? nextCapital(int c) => null;
 
   String toString() => keyword.lexeme;
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/reader.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/reader.dart
index 13460a4..4e073b7 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/reader.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/reader.dart
@@ -60,12 +60,12 @@
   /**
    * The number of characters in the string.
    */
-  int _stringLength;
+  late int _stringLength;
 
   /**
    * The index, relative to the string, of the next character to be read.
    */
-  int _charOffset;
+  late int _charOffset;
 
   /**
    * Initialize a newly created reader to read the characters in the given
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/recover.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/recover.dart
index 4a06122..c18e6b1 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/recover.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/recover.dart
@@ -22,14 +22,14 @@
   // Skip over prepended error tokens
   Token token = tokens;
   while (token is ErrorToken) {
-    token = token.next;
+    token = token.next!;
   }
 
   // Assert no error tokens in the remaining tokens
   while (!token.isEof) {
     if (token is ErrorToken) {
       for (int count = 0; count < 3; ++count) {
-        Token previous = token.previous;
+        Token previous = token.previous!;
         if (previous.isEof) break;
         token = previous;
       }
@@ -38,11 +38,11 @@
       for (int count = 0; count < 7; ++count) {
         if (token.isEof) break;
         msg.write(' ${token.runtimeType},');
-        token = token.next;
+        token = token.next!;
       }
       throw msg.toString();
     }
-    token = token.next;
+    token = token.next!;
   }
 
   return tokens;
@@ -54,7 +54,7 @@
 
 Token skipToEof(Token token) {
   while (!token.isEof) {
-    token = token.next;
+    token = token.next!;
   }
   return token;
 }
@@ -66,7 +66,7 @@
     '{': '}',
     '<': '>',
     r'${': '}',
-  }[openBrace];
+  }[openBrace]!;
 }
 
 String closeQuoteFor(String openQuote) {
@@ -79,5 +79,5 @@
     "r'": "'",
     'r"""': '"""',
     "r'''": "'''",
-  }[openQuote];
+  }[openQuote]!;
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart
index f8184e1..63fd51c 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart
@@ -68,9 +68,9 @@
 
 /// Scan/tokenize the given UTF8 [bytes].
 ScannerResult scan(List<int> bytes,
-    {ScannerConfiguration configuration,
+    {ScannerConfiguration? configuration,
     bool includeComments: false,
-    LanguageVersionChanged languageVersionChanged}) {
+    LanguageVersionChanged? languageVersionChanged}) {
   if (bytes.last != 0) {
     throw new ArgumentError("[bytes]: the last byte must be null.");
   }
@@ -83,9 +83,10 @@
 
 /// Scan/tokenize the given [source].
 ScannerResult scanString(String source,
-    {ScannerConfiguration configuration,
+    {ScannerConfiguration? configuration,
     bool includeComments: false,
-    LanguageVersionChanged languageVersionChanged}) {
+    LanguageVersionChanged? languageVersionChanged}) {
+  // ignore: unnecessary_null_comparison
   assert(source != null, 'source must not be null');
   StringScanner scanner = new StringScanner(source,
       configuration: configuration,
@@ -95,10 +96,10 @@
 }
 
 ScannerResult _tokenizeAndRecover(Scanner scanner,
-    {List<int> bytes, String source}) {
+    {List<int>? bytes, String? source}) {
   Token tokens = scanner.tokenize();
   if (scanner.hasErrors) {
-    if (bytes == null) bytes = utf8.encode(source);
+    if (bytes == null) bytes = utf8.encode(source!);
     tokens = scannerRecovery(bytes, tokens, scanner.lineStarts);
   }
   return new ScannerResult(tokens, scanner.lineStarts, scanner.hasErrors);
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/scanner_main.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/scanner_main.dart
index b0232dd..18c7c7e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/scanner_main.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/scanner_main.dart
@@ -25,7 +25,7 @@
 void printTokens(Token token) {
   while (!token.isEof) {
     print("${token.charOffset}: $token");
-    token = token.next;
+    token = token.next!;
   }
 }
 
@@ -35,7 +35,7 @@
 void verifyErrorTokens(Token firstToken, Uri uri) {
   Token token = firstToken;
   while (token is ErrorToken) {
-    token = token.next;
+    token = token.next!;
   }
 
   while (!token.isEof) {
@@ -49,11 +49,11 @@
       int count = 0;
       token = firstToken;
       while (token != errorToken) {
-        token = token.next;
+        token = token.next!;
         if (count < 10) {
           ++count;
         } else {
-          start = start.next;
+          start = start.next!;
         }
       }
 
@@ -62,12 +62,12 @@
       token = start;
       while (count < 20 && !token.isEof) {
         print("${token.charOffset}: $token");
-        token = token.next;
+        token = token.next!;
         ++count;
       }
       throw 'Out of order ErrorToken: $errorToken';
     }
-    token = token.next;
+    token = token.next!;
   }
 }
 
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/string_canonicalizer.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/string_canonicalizer.dart
index 7370bdf..a43887f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/string_canonicalizer.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/string_canonicalizer.dart
@@ -11,7 +11,7 @@
   int start;
   int end;
   String payload;
-  Node next;
+  Node? next;
   Node(this.data, this.start, this.end, this.payload, this.next);
 }
 
@@ -34,7 +34,7 @@
   int _count = 0;
 
   /// The table itself.
-  List<Node> _nodes = new List<Node>.filled(INITIAL_SIZE, null);
+  List<Node?> _nodes = new List<Node?>.filled(INITIAL_SIZE, null);
 
   static String decode(List<int> data, int start, int end, bool asciiOnly) {
     String s;
@@ -64,15 +64,15 @@
 
   rehash() {
     int newSize = _size * 2;
-    List<Node> newNodes = new List<Node>.filled(newSize, null);
+    List<Node?> newNodes = new List<Node?>.filled(newSize, null);
     for (int i = 0; i < _size; i++) {
-      Node t = _nodes[i];
+      Node? t = _nodes[i];
       while (t != null) {
-        Node n = t.next;
+        Node? n = t.next;
         int newIndex = t.data is String
             ? hashString(t.data, t.start, t.end) & (newSize - 1)
             : hashBytes(t.data, t.start, t.end) & (newSize - 1);
-        Node s = newNodes[newIndex];
+        Node? s = newNodes[newIndex];
         t.next = s;
         newNodes[newIndex] = t;
         t = n;
@@ -88,8 +88,8 @@
         ? hashString(data, start, end)
         : hashBytes(data, start, end);
     index = index & (_size - 1);
-    Node s = _nodes[index];
-    Node t = s;
+    Node? s = _nodes[index];
+    Node? t = s;
     int len = end - start;
     while (t != null) {
       if (t.end - t.start == len) {
@@ -117,7 +117,7 @@
 
   clear() {
     _size = INITIAL_SIZE;
-    _nodes = new List<Node>.filled(_size, null);
+    _nodes = new List<Node?>.filled(_size, null);
     _count = 0;
   }
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
index b09443e..4b15b5f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
@@ -22,15 +22,15 @@
  */
 class StringScanner extends AbstractScanner {
   /** The file content. */
-  String string;
+  late String string;
 
   /** The current offset in [string]. */
-  int scanOffset = -1;
+  late int scanOffset = -1;
 
   StringScanner(String string,
-      {ScannerConfiguration configuration,
+      {ScannerConfiguration? configuration,
       bool includeComments: false,
-      LanguageVersionChanged languageVersionChanged})
+      LanguageVersionChanged? languageVersionChanged})
       : string = ensureZeroTermination(string),
         super(configuration, includeComments, languageVersionChanged);
 
@@ -54,7 +54,7 @@
   static bool isLegalIdentifier(String identifier) {
     StringScanner scanner = new StringScanner(identifier);
     Token startToken = scanner.tokenize();
-    return startToken is! ErrorToken && startToken.next.isEof;
+    return startToken is! ErrorToken && startToken.next!.isEof;
   }
 
   int advance() => string.codeUnitAt(++scanOffset);
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart
index 38f0335..9ae4026 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart
@@ -39,13 +39,13 @@
   /**
    * The token that corresponds to this token.
    */
-  Token endToken;
+  Token? endToken;
 
   /**
    * Initialize a newly created token to have the given [type] at the given
    * [offset].
    */
-  BeginToken(TokenType type, int offset, [CommentToken precedingComment])
+  BeginToken(TokenType type, int offset, [CommentToken? precedingComment])
       : super(type, offset, precedingComment) {
     assert(type == TokenType.LT ||
         type == TokenType.OPEN_CURLY_BRACKET ||
@@ -58,12 +58,12 @@
   Token copy() => new BeginToken(type, offset, copyComments(precedingComments));
 
   @override
-  Token get endGroup => endToken;
+  Token? get endGroup => endToken;
 
   /**
    * Set the token that corresponds to this token.
    */
-  set endGroup(Token token) {
+  set endGroup(Token? token) {
     endToken = token;
   }
 }
@@ -75,7 +75,7 @@
   /**
    * The token that contains this comment.
    */
-  SimpleToken parent;
+  SimpleToken? parent;
 
   /**
    * Initialize a newly created token to represent a token of the given [type]
@@ -93,12 +93,13 @@
    * This is used when we decide to interpret the comment as syntax.
    */
   void remove() {
+    Token? previous = this.previous;
     if (previous != null) {
       previous.setNextWithoutSettingPrevious(next);
       next?.previous = previous;
     } else {
-      assert(parent.precedingComments == this);
-      parent.precedingComments = next;
+      assert(parent!.precedingComments == this);
+      parent!.precedingComments = next as CommentToken?;
     }
   }
 }
@@ -472,7 +473,7 @@
    * Initialize a newly created token to represent the given [keyword] at the
    * given [offset].
    */
-  KeywordToken(this.keyword, int offset, [CommentToken precedingComment])
+  KeywordToken(this.keyword, int offset, [CommentToken? precedingComment])
       : super(keyword, offset, precedingComment);
 
   @override
@@ -537,15 +538,15 @@
    * The previous token in the token stream.
    */
   @override
-  Token previous;
+  Token? previous;
 
   @override
-  Token next;
+  Token? next;
 
   /**
    * The first comment in the list of comments that precede this token.
    */
-  CommentToken _precedingComment;
+  CommentToken? _precedingComment;
 
   /**
    * Initialize a newly created token to have the given [type] and [offset].
@@ -564,10 +565,10 @@
   int get charEnd => end;
 
   @override
-  Token get beforeSynthetic => null;
+  Token? get beforeSynthetic => null;
 
   @override
-  set beforeSynthetic(Token previous) {
+  set beforeSynthetic(Token? previous) {
     // ignored
   }
 
@@ -575,7 +576,7 @@
   int get end => offset + length;
 
   @override
-  Token get endGroup => null;
+  Token? get endGroup => null;
 
   @override
   bool get isEof => type == TokenType.EOF;
@@ -605,7 +606,7 @@
   bool get isUserDefinableOperator => type.isUserDefinableOperator;
 
   @override
-  Keyword get keyword => null;
+  Keyword? get keyword => null;
 
   @override
   int get kind => type.kind;
@@ -617,31 +618,31 @@
   String get lexeme => type.lexeme;
 
   @override
-  CommentToken get precedingComments => _precedingComment;
+  CommentToken? get precedingComments => _precedingComment;
 
-  void set precedingComments(CommentToken comment) {
+  void set precedingComments(CommentToken? comment) {
     _precedingComment = comment;
     _setCommentParent(_precedingComment);
   }
 
   @override
-  String get stringValue => type.stringValue;
+  String? get stringValue => type.stringValue;
 
   @override
   Token copy() =>
       new SimpleToken(type, offset, copyComments(precedingComments));
 
   @override
-  Token copyComments(Token token) {
+  CommentToken? copyComments(CommentToken? token) {
     if (token == null) {
       return null;
     }
-    Token head = token.copy();
+    CommentToken head = token.copy();
     Token tail = head;
-    token = token.next;
+    token = token.next as CommentToken?;
     while (token != null) {
       tail = tail.setNext(token.copy());
-      token = token.next;
+      token = token.next as CommentToken?;
     }
     return head;
   }
@@ -665,7 +666,7 @@
   }
 
   @override
-  Token setNextWithoutSettingPrevious(Token token) {
+  Token? setNextWithoutSettingPrevious(Token? token) {
     next = token;
     return token;
   }
@@ -680,10 +681,10 @@
    * Sets the `parent` property to `this` for the given [comment] and all the
    * next tokens.
    */
-  void _setCommentParent(CommentToken comment) {
+  void _setCommentParent(CommentToken? comment) {
     while (comment != null) {
       comment.parent = this;
-      comment = comment.next;
+      comment = comment.next as CommentToken?;
     }
   }
 }
@@ -695,14 +696,14 @@
   /**
    * The lexeme represented by this token.
    */
-  String _value;
+  late String _value;
 
   /**
    * Initialize a newly created token to represent a token of the given [type]
    * with the given [value] at the given [offset].
    */
   StringToken(TokenType type, String value, int offset,
-      [CommentToken precedingComment])
+      [CommentToken? precedingComment])
       : super(type, offset, precedingComment) {
     this._value = StringUtilities.intern(value);
   }
@@ -730,7 +731,7 @@
    * [offset].
    */
   SyntheticBeginToken(TokenType type, int offset,
-      [CommentToken precedingComment])
+      [CommentToken? precedingComment])
       : super(type, offset, precedingComment);
 
   @override
@@ -765,7 +766,7 @@
  * A token whose value is independent of it's type.
  */
 class SyntheticStringToken extends StringToken {
-  final int _length;
+  final int? _length;
 
   /**
    * Initialize a newly created token to represent a token of the given [type]
@@ -792,7 +793,7 @@
   SyntheticToken(TokenType type, int offset) : super(type, offset);
 
   @override
-  Token beforeSynthetic;
+  Token? beforeSynthetic;
 
   @override
   bool get isSynthetic => true;
@@ -818,7 +819,7 @@
   }
 
   @override
-  Token beforeSynthetic;
+  Token? beforeSynthetic;
 
   @override
   bool get isSynthetic => true;
@@ -840,13 +841,13 @@
   /**
    * Initialize a newly created token to have the given [type] and [offset].
    */
-  factory Token(TokenType type, int offset, [CommentToken preceedingComment]) =
+  factory Token(TokenType type, int offset, [CommentToken? preceedingComment]) =
       SimpleToken;
 
   /**
    * Initialize a newly created end-of-file token to have the given [offset].
    */
-  factory Token.eof(int offset, [CommentToken precedingComments]) {
+  factory Token.eof(int offset, [CommentToken? precedingComments]) {
     Token eof = new SimpleToken(TokenType.EOF, offset, precedingComments);
     // EOF points to itself so there's always infinite look-ahead.
     eof.previous = eof;
@@ -873,13 +874,13 @@
    * The token before this synthetic token,
    * or `null` if this is not a synthetic `)`, `]`, `}`, or `>` token.
    */
-  Token get beforeSynthetic;
+  Token? get beforeSynthetic;
 
   /**
    * Set token before this synthetic `)`, `]`, `}`, or `>` token,
    * and ignored otherwise.
    */
-  set beforeSynthetic(Token previous);
+  set beforeSynthetic(Token? previous);
 
   @override
   int get end;
@@ -888,7 +889,7 @@
    * The token that corresponds to this token, or `null` if this token is not
    * the first of a pair of matching tokens (such as parentheses).
    */
-  Token get endGroup => null;
+  Token? get endGroup => null;
 
   /**
    * Return `true` if this token represents an end of file.
@@ -944,7 +945,7 @@
   /**
    * Return the keyword, if a keyword token, or `null` otherwise.
    */
-  Keyword get keyword;
+  Keyword? get keyword;
 
   /**
    * The kind enum of this token as determined by its [type].
@@ -964,12 +965,12 @@
   /**
    * Return the next token in the token stream.
    */
-  Token get next;
+  Token? get next;
 
   /**
    * Return the next token in the token stream.
    */
-  void set next(Token next);
+  void set next(Token? next);
 
   @override
   int get offset;
@@ -990,17 +991,17 @@
    * the first preceding comment token will have a lexeme of `/* one */` and
    * the next comment token will have a lexeme of `/* two */`.
    */
-  CommentToken get precedingComments;
+  CommentToken? get precedingComments;
 
   /**
    * Return the previous token in the token stream.
    */
-  Token get previous;
+  Token? get previous;
 
   /**
    * Set the previous token in the token stream to the given [token].
    */
-  void set previous(Token token);
+  void set previous(Token? token);
 
   /**
    * For symbol and keyword tokens, returns the string value represented by this
@@ -1020,7 +1021,7 @@
    * declaration using [:identical(next.stringValue, '('):], which (rightfully)
    * returns false because stringValue returns [:null:].
    */
-  String get stringValue;
+  String? get stringValue;
 
   /**
    * Return the type of the token.
@@ -1037,7 +1038,7 @@
   /**
    * Copy a linked list of comment tokens identical to the given comment tokens.
    */
-  Token copyComments(Token token);
+  CommentToken? copyComments(CommentToken? token);
 
   /**
    * Return `true` if this token has any one of the given [types].
@@ -1056,7 +1057,7 @@
    * which token is the previous token for the given token. Return the token
    * that was passed in.
    */
-  Token setNextWithoutSettingPrevious(Token token);
+  Token? setNextWithoutSettingPrevious(Token? token);
 
   /**
    * Returns a textual representation of this token to be used for debugging
@@ -1083,12 +1084,12 @@
    * `null`. Return the token with the smallest offset, or `null` if the list is
    * empty or if all of the elements of the list are `null`.
    */
-  static Token lexicallyFirst(List<Token> tokens) {
-    Token first = null;
+  static Token? lexicallyFirst(List<Token?> tokens) {
+    Token? first = null;
     int offset = -1;
     int length = tokens.length;
     for (int i = 0; i < length; i++) {
-      Token token = tokens[i];
+      Token? token = tokens[i];
       if (token != null && (offset < 0 || token.offset < offset)) {
         first = token;
         offset = token.offset;
@@ -1693,14 +1694,14 @@
   /**
    * See [Token.stringValue] for an explanation.
    */
-  final String stringValue;
+  final String? stringValue;
 
   const TokenType(this.lexeme, this.name, this.precedence, this.kind,
       {this.isModifier: false,
       this.isOperator: false,
       this.isTopLevelKeyword: false,
       this.isUserDefinableOperator: false,
-      String stringValue: 'unspecified'})
+      String? stringValue: 'unspecified'})
       : this.stringValue = stringValue == 'unspecified' ? lexeme : stringValue;
 
   /**
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
index a42b728..3c84db5 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
@@ -34,7 +34,7 @@
    * is canonicalized before the token is created.
    */
   StringToken.fromString(TokenType type, String value, int charOffset,
-      {bool canonicalize: false, analyzer.CommentToken precedingComments})
+      {bool canonicalize: false, analyzer.CommentToken? precedingComments})
       : valueOrLazySubstring = canonicalizedString(
             value, /* start = */ 0, value.length, canonicalize),
         super(type, charOffset, precedingComments);
@@ -45,7 +45,7 @@
    */
   StringToken.fromSubstring(
       TokenType type, String data, int start, int end, int charOffset,
-      {bool canonicalize: false, analyzer.CommentToken precedingComments})
+      {bool canonicalize: false, analyzer.CommentToken? precedingComments})
       : super(type, charOffset, precedingComments) {
     int length = end - start;
     if (length <= LAZY_THRESHOLD) {
@@ -63,7 +63,7 @@
    */
   StringToken.fromUtf8Bytes(TokenType type, List<int> data, int start, int end,
       bool asciiOnly, int charOffset,
-      {analyzer.CommentToken precedingComments})
+      {analyzer.CommentToken? precedingComments})
       : super(type, charOffset, precedingComments) {
     int length = end - start;
     if (length <= LAZY_THRESHOLD) {
@@ -74,7 +74,7 @@
   }
 
   StringToken._(TokenType type, this.valueOrLazySubstring, int charOffset,
-      [analyzer.CommentToken precedingComments])
+      [analyzer.CommentToken? precedingComments])
       : super(type, charOffset, precedingComments);
 
   @override
@@ -85,7 +85,7 @@
       assert(valueOrLazySubstring is _LazySubstring);
       dynamic data = valueOrLazySubstring.data;
       int start = valueOrLazySubstring.start;
-      int end = start + valueOrLazySubstring.length;
+      int end = start + (valueOrLazySubstring as _LazySubstring).length;
       if (data is String) {
         valueOrLazySubstring = canonicalizedString(
             data, start, end, valueOrLazySubstring.boolValue);
@@ -129,7 +129,7 @@
 class SyntheticStringToken extends StringToken
     implements analyzer.SyntheticStringToken {
   SyntheticStringToken(TokenType type, String value, int offset,
-      [analyzer.CommentToken precedingComments])
+      [analyzer.CommentToken? precedingComments])
       : super._(type, value, offset, precedingComments);
 
   @override
@@ -142,7 +142,7 @@
 
 class CommentToken extends StringToken implements analyzer.CommentToken {
   @override
-  analyzer.SimpleToken parent;
+  analyzer.SimpleToken? parent;
 
   /**
    * Creates a lazy comment token. If [canonicalize] is true, the string
@@ -178,11 +178,11 @@
   @override
   void remove() {
     if (previous != null) {
-      previous.setNextWithoutSettingPrevious(next);
+      previous!.setNextWithoutSettingPrevious(next);
       next?.previous = previous;
     } else {
-      assert(parent.precedingComments == this);
-      parent.precedingComments = next as CommentToken;
+      assert(parent!.precedingComments == this);
+      parent!.precedingComments = next as CommentToken;
     }
   }
 }
@@ -200,7 +200,7 @@
 
   LanguageVersionToken.fromSubstring(
       String string, int start, int end, int tokenStart, this.major, this.minor,
-      {bool canonicalize})
+      {bool canonicalize: false})
       : super.fromSubstring(
             TokenType.SINGLE_LINE_COMMENT, string, start, end, tokenStart,
             canonicalize: canonicalize);
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
index f55b9ee..9ef6fd2 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
@@ -28,7 +28,7 @@
    *
    * The content is zero-terminated.
    */
-  List<int> bytes;
+  late List<int> bytes;
 
   /**
    * Points to the offset of the last byte returned by [advance].
@@ -84,9 +84,9 @@
    * is not the case, the entire array is copied before scanning.
    */
   Utf8BytesScanner(this.bytes,
-      {ScannerConfiguration configuration,
+      {ScannerConfiguration? configuration,
       bool includeComments: false,
-      LanguageVersionChanged languageVersionChanged})
+      LanguageVersionChanged? languageVersionChanged})
       : super(configuration, includeComments, languageVersionChanged,
             numberOfBytesHint: bytes.length) {
     assert(bytes.last == 0);
diff --git a/pkg/_fe_analyzer_shared/lib/src/sdk/allowed_experiments.dart b/pkg/_fe_analyzer_shared/lib/src/sdk/allowed_experiments.dart
index a7faa11..50a1e65 100644
--- a/pkg/_fe_analyzer_shared/lib/src/sdk/allowed_experiments.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/sdk/allowed_experiments.dart
@@ -4,8 +4,6 @@
 
 import 'dart:convert';
 
-import 'package:meta/meta.dart';
-
 /// Parse the given [jsonText] into the [AllowedExperiments].
 ///
 /// Throw [FormatException] is any format issues are found.
@@ -28,14 +26,14 @@
   final Map<String, List<String>> packageExperiments;
 
   AllowedExperiments({
-    @required this.sdkDefaultExperiments,
-    @required this.sdkLibraryExperiments,
-    @required this.packageExperiments,
+    required this.sdkDefaultExperiments,
+    required this.sdkLibraryExperiments,
+    required this.packageExperiments,
   });
 
   /// Return the set of enabled experiments for the package with the [name],
   /// e.g. "path", possibly `null`.
-  List<String> forPackage(String name) {
+  List<String>? forPackage(String name) {
     return packageExperiments[name];
   }
 
@@ -55,14 +53,14 @@
 
   AllowedExperiments parse() {
     Object rootObject = json.decode(_jsonText);
-    Map<String, Object> map = _mustBeMap(rootObject);
+    Map<String, Object?> map = _mustBeMap(rootObject);
 
     _ensureVersion(map);
 
     _withParsePath('experimentSets', () {
-      Map<String, Object> experimentSetMap =
+      Map<String, Object?> experimentSetMap =
           _requiredMap(map, 'experimentSets');
-      for (MapEntry<String, Object> entry in experimentSetMap.entries) {
+      for (MapEntry<String, Object?> entry in experimentSetMap.entries) {
         String setName = entry.key;
         _withParsePath(setName, () {
           _experimentSets[setName] = _mustBeListOfStrings(entry.value);
@@ -73,7 +71,7 @@
     List<String> sdkDefaultExperimentSet = <String>[];
     Map<String, List<String>> sdkLibraryExperiments = <String, List<String>>{};
     _withParsePath('sdk', () {
-      Map<String, Object> sdkMap = _requiredMap(map, 'sdk');
+      Map<String, Object?> sdkMap = _requiredMap(map, 'sdk');
 
       _withParsePath('default', () {
         sdkDefaultExperimentSet = _experimentList(
@@ -82,14 +80,14 @@
       });
 
       _withParsePath('libraries', () {
-        Map<String, Object> sdkLibraryExperimentsMap =
+        Map<String, Object?>? sdkLibraryExperimentsMap =
             _optionalMap(sdkMap, 'libraries');
         if (sdkLibraryExperimentsMap != null) {
-          for (MapEntry<String, Object> entry
+          for (MapEntry<String, Object?> entry
               in sdkLibraryExperimentsMap.entries) {
             String libraryName = entry.key;
             _withParsePath(libraryName, () {
-              Map<String, Object> libraryMap = _mustBeMap(entry.value);
+              Map<String, Object?> libraryMap = _mustBeMap(entry.value);
               List<String> experimentList = _experimentList(libraryMap);
               sdkLibraryExperiments[libraryName] = experimentList;
             });
@@ -100,12 +98,13 @@
 
     Map<String, List<String>> packageExperiments = <String, List<String>>{};
     _withParsePath('packages', () {
-      Map<String, Object> packageExperimentsMap = _optionalMap(map, 'packages');
+      Map<String, Object?>? packageExperimentsMap =
+          _optionalMap(map, 'packages');
       if (packageExperimentsMap != null) {
-        for (MapEntry<String, Object> entry in packageExperimentsMap.entries) {
+        for (MapEntry<String, Object?> entry in packageExperimentsMap.entries) {
           String packageName = entry.key;
           _withParsePath(packageName, () {
-            Map<String, Object> libraryMap = _mustBeMap(entry.value);
+            Map<String, Object?> libraryMap = _mustBeMap(entry.value);
             List<String> experimentList = _experimentList(libraryMap);
             packageExperiments[packageName] = experimentList;
           });
@@ -120,8 +119,8 @@
     );
   }
 
-  void _ensureVersion(Map<String, Object> map) {
-    Object versionObject = map['version'];
+  void _ensureVersion(Map<String, Object?> map) {
+    Object? versionObject = map['version'];
     if (versionObject is! int || versionObject != 1) {
       throw new FormatException(
         "Expected field 'version' with value '1'; "
@@ -131,9 +130,9 @@
     }
   }
 
-  List<String> _experimentList(Map<String, Object> map) {
+  List<String> _experimentList(Map<String, Object?> map) {
     String experimentSetName = _requiredString(map, 'experimentSet');
-    List<String> result = _experimentSets[experimentSetName];
+    List<String>? result = _experimentSets[experimentSetName];
     if (result != null) {
       return result;
     }
@@ -144,8 +143,8 @@
     );
   }
 
-  List<String> _mustBeListOfStrings(Object object) {
-    if (object is List<Object> && object.every((e) => e is String)) {
+  List<String> _mustBeListOfStrings(Object? object) {
+    if (object is List<Object?> && object.every((e) => e is String)) {
       return List.castFrom(object);
     }
 
@@ -157,8 +156,8 @@
     );
   }
 
-  Map<String, Object> _mustBeMap(Object object) {
-    if (object is Map<String, Object>) {
+  Map<String, Object?> _mustBeMap(Object? object) {
+    if (object is Map<String, Object?>) {
       return object;
     }
 
@@ -170,9 +169,9 @@
     );
   }
 
-  Map<String, Object> _optionalMap(Map<String, Object> map, String name) {
-    Object result = map[name];
-    if (result == null || result is Map<String, Object>) {
+  Map<String, Object?>? _optionalMap(Map<String, Object?> map, String name) {
+    Object? result = map[name];
+    if (result is Map<String, Object?>?) {
       return result;
     }
 
@@ -183,9 +182,9 @@
     );
   }
 
-  Map<String, Object> _requiredMap(Map<String, Object> map, String name) {
-    Object result = map[name];
-    if (result is Map<String, Object>) {
+  Map<String, Object?> _requiredMap(Map<String, Object?> map, String name) {
+    Object? result = map[name];
+    if (result is Map<String, Object?>) {
       return result;
     }
 
@@ -196,8 +195,8 @@
     );
   }
 
-  String _requiredString(Map<String, Object> map, String name) {
-    Object result = map[name];
+  String _requiredString(Map<String, Object?> map, String name) {
+    Object? result = map[name];
     if (result is String) {
       return result;
     }
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/annotated_code_helper.dart b/pkg/_fe_analyzer_shared/lib/src/testing/annotated_code_helper.dart
index d4cb830..000d994 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/annotated_code_helper.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/annotated_code_helper.dart
@@ -15,7 +15,7 @@
   /// The index of the (corresponding) annotation in the annotated code test, or
   /// `null` if the annotation doesn't correspond to an annotation in the
   /// annotated code.
-  final int index;
+  final int? index;
 
   /// 1-based line number of the annotation.
   final int lineNo;
@@ -37,6 +37,7 @@
 
   Annotation(this.index, this.lineNo, this.columnNo, this.offset, this.prefix,
       this.text, this.suffix)
+      // ignore: unnecessary_null_comparison
       : assert(offset != null),
         assert(offset >= 0);
 
@@ -71,7 +72,7 @@
   /// The annotations for the source code.
   final List<Annotation> annotations;
 
-  List<int> _lineStarts;
+  List<int>? _lineStarts;
 
   AnnotatedCode(this.annotatedCode, this.sourceCode, this.annotations);
 
@@ -92,7 +93,7 @@
     List<int> lineStarts = <int>[];
     lineStarts.add(offset);
     while (index < annotatedCode.length) {
-      Match startMatch = start.matchAsPrefix(annotatedCode, index);
+      Match? startMatch = start.matchAsPrefix(annotatedCode, index);
       if (startMatch != null) {
         int startIndex = startMatch.end;
         Iterable<Match> endMatches =
@@ -145,16 +146,17 @@
 
   void _ensureLineStarts() {
     if (_lineStarts == null) {
+      List<int> lineStarts = <int>[];
+      _lineStarts = lineStarts;
       int index = 0;
       int offset = 0;
-      _lineStarts = <int>[];
-      _lineStarts.add(offset);
+      lineStarts.add(offset);
       while (index < sourceCode.length) {
         int charCode = sourceCode.codeUnitAt(index);
         switch (charCode) {
           case _LF:
             offset++;
-            _lineStarts.add(offset);
+            lineStarts.add(offset);
             break;
           case _CR:
             if (index + 1 < sourceCode.length &&
@@ -162,35 +164,35 @@
               index++;
             }
             offset++;
-            _lineStarts.add(offset);
+            lineStarts.add(offset);
             break;
           default:
             offset++;
         }
         index++;
       }
-      _lineStarts.add(offset);
+      lineStarts.add(offset);
     }
   }
 
   void addAnnotation(
       int lineNo, int columnNo, String prefix, String text, String suffix) {
     _ensureLineStarts();
-    int offset = _lineStarts[lineNo - 1] + (columnNo - 1);
+    int offset = _lineStarts![lineNo - 1] + (columnNo - 1);
     annotations.add(new Annotation(
         annotations.length, lineNo, columnNo, offset, prefix, text, suffix));
   }
 
   int get lineCount {
     _ensureLineStarts();
-    return _lineStarts.length;
+    return _lineStarts!.length;
   }
 
   int getLineIndex(int offset) {
     _ensureLineStarts();
     int index = 0;
-    while (index + 1 < _lineStarts.length) {
-      if (_lineStarts[index + 1] <= offset) {
+    while (index + 1 < _lineStarts!.length) {
+      if (_lineStarts![index + 1] <= offset) {
         index++;
       } else {
         break;
@@ -203,8 +205,8 @@
     _ensureLineStarts();
     if (lineIndex < 0) {
       return 0;
-    } else if (lineIndex < _lineStarts.length) {
-      return _lineStarts[lineIndex];
+    } else if (lineIndex < _lineStarts!.length) {
+      return _lineStarts![lineIndex];
     } else {
       return sourceCode.length;
     }
@@ -223,7 +225,7 @@
         int result = a.offset.compareTo(b.offset);
         if (result == 0) {
           if (a.index != null && b.index != null) {
-            result = a.index.compareTo(b.index);
+            result = a.index!.compareTo(b.index!);
           } else if (a.index != null) {
             result = -1;
           } else if (b.index != null) {
@@ -286,13 +288,13 @@
               annotation.prefix,
               annotationText,
               annotation.suffix);
-          map[part].add(subAnnotation);
+          map[part]!.add(subAnnotation);
         }
         continue outer;
       }
     }
     for (String prefix in prefixSet) {
-      map[prefix].add(annotation);
+      map[prefix]!.add(annotation);
     }
   }
   Map<String, AnnotatedCode> split = <String, AnnotatedCode>{};
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/features.dart b/pkg/_fe_analyzer_shared/lib/src/testing/features.dart
index 79072a1..113d1d8 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/features.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/features.dart
@@ -36,7 +36,8 @@
 
   /// Add [value] as an element of the list values of feature [key].
   void addElement(String key, [var value]) {
-    List<String> list = _features.putIfAbsent(key, () => <String>[]);
+    List<String> list =
+        _features.putIfAbsent(key, () => <String>[]) as List<String>;
     if (value != null) {
       list.add(value.toString());
     }
@@ -59,10 +60,10 @@
   }
 
   /// Returns the value set for feature [key].
-  Object operator [](String key) => _features[key];
+  Object? operator [](String key) => _features[key];
 
   /// Removes the value set for feature [key]. Returns the existing value.
-  Object remove(String key) => _features.remove(key);
+  Object? remove(String key) => _features.remove(key);
 
   /// Returns `true` if this feature set is empty.
   bool get isEmpty => _features.isEmpty;
@@ -78,7 +79,7 @@
 
   /// Returns a string containing all features in a comma-separated list sorted
   /// by feature names.
-  String getText([String indent]) {
+  String getText([String? indent]) {
     if (indent == null) {
       StringBuffer sb = new StringBuffer();
       bool needsComma = false;
@@ -155,7 +156,7 @@
   ///
   /// Single features will be parsed as strings and list features (features
   /// encoded in `[...]` will be parsed as lists of strings.
-  static Features fromText(String text) {
+  static Features fromText(String? text) {
     Features features = new Features();
     if (text == null) return features;
     int index = 0;
@@ -205,7 +206,7 @@
             endDelimiters.removeLast();
             index++;
           } else {
-            String endDelimiter = delimiters[char];
+            String? endDelimiter = delimiters[char];
             if (endDelimiter != null) {
               endDelimiters.add(endDelimiter);
               index++;
@@ -244,12 +245,12 @@
 }
 
 class FeaturesDataInterpreter implements DataInterpreter<Features> {
-  final String wildcard;
+  final String? wildcard;
 
-  const FeaturesDataInterpreter({this.wildcard: null});
+  const FeaturesDataInterpreter({this.wildcard});
 
   @override
-  String isAsExpected(Features actualFeatures, String expectedData) {
+  String? isAsExpected(Features actualFeatures, String? expectedData) {
     if (wildcard != null && expectedData == wildcard) {
       return null;
     } else if (expectedData == '') {
@@ -265,7 +266,7 @@
           expectMatch = false;
         }
         validatedFeatures.add(key);
-        Object actualValue = actualFeatures[key];
+        Object? actualValue = actualFeatures[key];
         if (!expectMatch) {
           if (actualFeatures.containsKey(key)) {
             errorsFound.add('Unexpected data found for $key=$actualValue');
@@ -284,10 +285,10 @@
             for (Object expectedObject in expectedValue) {
               String expectedText = '$expectedObject';
               bool matchFound = false;
-              if (wildcard != null && expectedText.endsWith(wildcard)) {
+              if (wildcard != null && expectedText.endsWith(wildcard!)) {
                 // Wildcard matcher.
                 String prefix =
-                    expectedText.substring(0, expectedText.indexOf(wildcard));
+                    expectedText.substring(0, expectedText.indexOf(wildcard!));
                 List matches = [];
                 for (Object actualObject in actualList) {
                   if ('$actualObject'.startsWith(prefix)) {
@@ -338,12 +339,12 @@
   }
 
   @override
-  String getText(Features actualData, [String indentation]) {
+  String getText(Features actualData, [String? indentation]) {
     return actualData.getText(indentation);
   }
 
   @override
-  bool isEmpty(Features actualData) {
+  bool isEmpty(Features? actualData) {
     return actualData == null || actualData.isEmpty;
   }
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/id.dart b/pkg/_fe_analyzer_shared/lib/src/testing/id.dart
index 77377cd..f2821d2 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/id.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/id.dart
@@ -83,10 +83,10 @@
   static String idToString(Id id, String value) {
     switch (id.kind) {
       case IdKind.member:
-        MemberId elementId = id;
+        MemberId elementId = id as MemberId;
         return '$memberPrefix${elementId.name}:$value';
       case IdKind.cls:
-        ClassId classId = id;
+        ClassId classId = id as ClassId;
         return '$classPrefix${classId.name}:$value';
       case IdKind.library:
         return '$libraryPrefix$value';
@@ -109,7 +109,6 @@
       case IdKind.error:
         return '$errorPrefix$value';
     }
-    throw new UnsupportedError("Unexpected id kind: ${id.kind}");
   }
 
   static const String globalPrefix = "global#";
@@ -199,7 +198,7 @@
 
 /// Id for an member element.
 class MemberId implements Id {
-  final String className;
+  final String? className;
   final String memberName;
   @override
   final bool isGlobal;
@@ -307,7 +306,9 @@
   final IdKind kind;
 
   const NodeId(this.value, this.kind)
-      : assert(value != null),
+      :
+        // ignore: unnecessary_null_comparison
+        assert(value != null),
         assert(value >= 0);
 
   @override
@@ -341,7 +342,7 @@
 
   int get offset {
     if (id is NodeId) {
-      NodeId nodeId = id;
+      NodeId nodeId = id as NodeId;
       return nodeId.value;
     } else {
       return _offset;
@@ -367,8 +368,8 @@
     if (value != null) {
       ActualData<T> newData = new ActualData<T>(id, value, uri, offset, object);
       if (actualMap.containsKey(id)) {
-        ActualData<T> existingData = actualMap[id];
-        ActualData<T> mergedData = mergeData(existingData, newData);
+        ActualData<T> existingData = actualMap[id]!;
+        ActualData<T>? mergedData = mergeData(existingData, newData);
         if (mergedData != null) {
           actualMap[id] = mergedData;
         } else {
@@ -391,7 +392,7 @@
     }
   }
 
-  ActualData<T> mergeData(ActualData<T> value1, ActualData<T> value2) => null;
+  ActualData<T>? mergeData(ActualData<T> value1, ActualData<T> value2) => null;
 
   /// Called to report duplicate errors.
   void report(Uri uri, int offset, String message);
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/id_generation.dart b/pkg/_fe_analyzer_shared/lib/src/testing/id_generation.dart
index dd3fdb7e..896c670 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/id_generation.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/id_generation.dart
@@ -12,14 +12,14 @@
     Uri mainUri,
     Map<String, Map<Uri, Map<Id, ActualData<T>>>> actualData,
     DataInterpreter<T> dataInterpreter,
-    {Annotation Function(Annotation expected, Annotation actual) createDiff,
+    {Annotation? Function(Annotation? expected, Annotation? actual)? createDiff,
     bool forceUpdate: false}) {
   Set<Uri> uriSet = {};
   Set<String> actualMarkers = actualData.keys.toSet();
   Map<Uri, Map<Id, Map<String, IdValue>>> idValuePerUri = {};
   Map<Uri, Map<Id, Map<String, ActualData<T>>>> actualDataPerUri = {};
 
-  void addData(String marker, Uri uri, Map<Id, IdValue> data) {
+  void addData(String marker, Uri? uri, Map<Id, IdValue> data) {
     if (uri == null) {
       // TODO(johnniwinther): Avoid `null` URIs.
       assert(data.isEmpty, "Non-empty data without uri: $data");
@@ -43,6 +43,7 @@
   actualData
       .forEach((String marker, Map<Uri, Map<Id, ActualData<T>>> dataPerUri) {
     dataPerUri.forEach((Uri uri, Map<Id, ActualData<T>> dataMap) {
+      // ignore: unnecessary_null_comparison
       if (uri == null) {
         // TODO(johnniwinther): Avoid `null` URIs.
         assert(dataMap.isEmpty, "Non-empty data for `null` uri: $dataMap");
@@ -64,8 +65,9 @@
     Map<Id, Map<String, IdValue>> idValuePerId = idValuePerUri[uri] ?? {};
     Map<Id, Map<String, ActualData<T>>> actualDataPerId =
         actualDataPerUri[uri] ?? {};
-    AnnotatedCode code = annotatedCode[uri];
+    AnnotatedCode code = annotatedCode[uri]!;
     assert(
+        // ignore: unnecessary_null_comparison
         code != null, "No annotated code for ${uri} in ${annotatedCode.keys}");
     result[uri] = _computeAnnotations(code, expectedMaps.keys, actualMarkers,
         idValuePerId, actualDataPerId, dataInterpreter,
@@ -84,12 +86,13 @@
     {String defaultPrefix: '/*',
     String defaultSuffix: '*/',
     bool sortMarkers: true,
-    Annotation Function(Annotation expected, Annotation actual) createDiff,
+    Annotation? Function(Annotation? expected, Annotation? actual)? createDiff,
     bool forceUpdate: false}) {
+  // ignore: unnecessary_null_comparison
   assert(annotatedCode != null);
 
   Annotation createAnnotationFromData(
-      ActualData<T> actualData, Annotation annotation) {
+      ActualData<T> actualData, Annotation? annotation) {
     String getIndentationFromOffset(int offset) {
       int lineIndex = annotatedCode.getLineIndex(offset);
       String line = annotatedCode.getLine(lineIndex);
@@ -161,10 +164,10 @@
 
     Map<String, Annotation> newAnnotationsPerMarker = {};
     for (String marker in supportedMarkers) {
-      IdValue idValue = idValuePerMarker[marker];
-      ActualData<T> actualData = actualDataPerMarker[marker];
-      Annotation expectedAnnotation;
-      Annotation actualAnnotation;
+      IdValue? idValue = idValuePerMarker[marker];
+      ActualData<T>? actualData = actualDataPerMarker[marker];
+      Annotation? expectedAnnotation;
+      Annotation? actualAnnotation;
       if (idValue != null && actualData != null) {
         if (dataInterpreter.isAsExpected(actualData.value, idValue.value) ==
                 null &&
@@ -187,7 +190,7 @@
           actualAnnotation = createAnnotationFromData(actualData, null);
         }
       }
-      Annotation annotation = createDiff != null
+      Annotation? annotation = createDiff != null
           ? createDiff(expectedAnnotation, actualAnnotation)
           : actualAnnotation;
       if (annotation != null) {
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart b/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
index 6ef8308..4149cca 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
@@ -112,7 +112,7 @@
 
 /// Creates an annotation that shows the difference between [expected] and
 /// [actual].
-Annotation createAnnotationsDiff(Annotation expected, Annotation actual) {
+Annotation? createAnnotationsDiff(Annotation? expected, Annotation? actual) {
   if (identical(expected, actual)) return null;
   if (expected != null && actual != null) {
     return new Annotation(
@@ -173,7 +173,7 @@
     _computedDataForEachFile.forEach(f);
   }
 
-  Map<Id, DataType> operator [](Uri file) {
+  Map<Id, DataType>? operator [](Uri file) {
     if (!_computedDataForEachFile.containsKey(file)) {
       _computedDataForEachFile[file] = <Id, DataType>{};
     }
@@ -216,16 +216,17 @@
 // TODO(johnniwinther): Support an empty marker set.
 void computeExpectedMap(Uri sourceUri, String filename, AnnotatedCode code,
     Map<String, MemberAnnotations<IdValue>> maps,
-    {void onFailure(String message),
+    {required void onFailure(String message),
     bool preserveWhitespaceInAnnotations: false,
     bool preserveInfixWhitespaceInAnnotations: false}) {
   List<String> mapKeys = maps.keys.toList();
   Map<String, AnnotatedCode> split = splitByPrefixes(code, mapKeys);
 
   split.forEach((String marker, AnnotatedCode code) {
-    MemberAnnotations<IdValue> fileAnnotations = maps[marker];
+    MemberAnnotations<IdValue> fileAnnotations = maps[marker]!;
+    // ignore: unnecessary_null_comparison
     assert(fileAnnotations != null, "No annotations for $marker in $maps");
-    Map<Id, IdValue> expectedValues = fileAnnotations[sourceUri];
+    Map<Id, IdValue> expectedValues = fileAnnotations[sourceUri]!;
     for (Annotation annotation in code.annotations) {
       String text = annotation.text;
       IdValue idValue = IdValue.decode(sourceUri, annotation, text,
@@ -258,17 +259,17 @@
 /// If [testLibDirectory] is not `null`, files in [testLibDirectory] with the
 /// [testFile] name as a prefix are included.
 TestData computeTestData(FileSystemEntity testFile,
-    {Iterable<String> supportedMarkers,
-    Uri createTestUri(Uri uri, String fileName),
-    void onFailure(String message),
+    {required Iterable<String> supportedMarkers,
+    required Uri createTestUri(Uri uri, String fileName),
+    required void onFailure(String message),
     bool preserveWhitespaceInAnnotations: false,
     bool preserveInfixWhitespaceInAnnotations: false}) {
-  Uri entryPoint;
+  Uri? entryPoint;
 
   String testName;
-  File mainTestFile;
+  File? mainTestFile;
   Uri testFileUri = testFile.uri;
-  Map<String, File> additionalFiles;
+  Map<String, File>? additionalFiles;
   if (testFile is File) {
     testName = testFileUri.pathSegments.last;
     mainTestFile = testFile;
@@ -290,11 +291,13 @@
     }
     assert(
         mainTestFile != null, "No 'main.dart' test file found for $testFile.");
+  } else {
+    throw new UnimplementedError();
   }
 
-  String annotatedCode = new File.fromUri(mainTestFile.uri).readAsStringSync();
+  String annotatedCode = new File.fromUri(mainTestFile!.uri).readAsStringSync();
   Map<Uri, AnnotatedCode> code = {
-    entryPoint:
+    entryPoint!:
         new AnnotatedCode.fromText(annotatedCode, commentStart, commentEnd)
   };
   Map<String, MemberAnnotations<IdValue>> expectedMaps = {};
@@ -302,13 +305,13 @@
     expectedMaps[testMarker] = new MemberAnnotations<IdValue>();
   }
   computeExpectedMap(entryPoint, testFile.uri.pathSegments.last,
-      code[entryPoint], expectedMaps,
+      code[entryPoint]!, expectedMaps,
       onFailure: onFailure,
       preserveWhitespaceInAnnotations: preserveWhitespaceInAnnotations,
       preserveInfixWhitespaceInAnnotations:
           preserveInfixWhitespaceInAnnotations);
   Map<String, String> memorySourceFiles = {
-    entryPoint.path: code[entryPoint].sourceCode
+    entryPoint.path: code[entryPoint]!.sourceCode
   };
 
   if (additionalFiles != null) {
@@ -356,10 +359,10 @@
   final bool isErroneous;
 
   /// The data interpreter used to verify the [compiledData].
-  final DataInterpreter<T> interpreter;
+  final DataInterpreter<T>? interpreter;
 
   /// The actual data computed for the test.
-  final CompiledData<T> compiledData;
+  final CompiledData<T>? compiledData;
 
   TestResult(this.interpreter, this.compiledData, this.hasMismatches)
       : isErroneous = false;
@@ -389,7 +392,7 @@
   CompiledData(this.mainUri, this.actualMaps, this.globalData);
 
   Map<int, List<String>> computeAnnotations(Uri uri) {
-    Map<Id, ActualData<T>> actualMap = actualMaps[uri];
+    Map<Id, ActualData<T>> actualMap = actualMaps[uri]!;
     Map<int, List<String>> annotations = <int, List<String>>{};
     actualMap.forEach((Id id, ActualData<T> data) {
       String value1 = '${data.value}';
@@ -405,7 +408,7 @@
       {bool includeMatches: false}) {
     Map<int, List<String>> annotations = <int, List<String>>{};
     thisMap.forEach((Id id, ActualData<T> thisData) {
-      ActualData<T> otherData = otherMap[id];
+      ActualData<T>? otherData = otherMap[id];
       String thisValue = '${thisData.value}';
       if (thisData.value != otherData?.value) {
         String otherValue = '${otherData?.value ?? '---'}';
@@ -440,7 +443,7 @@
   /// Returns `null` if [actualData] satisfies the [expectedData] annotation.
   /// Otherwise, a message is returned contain the information about the
   /// problems found.
-  String isAsExpected(T actualData, String expectedData);
+  String? isAsExpected(T actualData, String? expectedData);
 
   /// Returns `true` if [actualData] corresponds to empty data.
   bool isEmpty(T actualData);
@@ -449,7 +452,7 @@
   ///
   /// If [indentation] is provided a multiline pretty printing can be returned
   /// using [indentation] for additional lines.
-  String getText(T actualData, [String indentation]);
+  String getText(T actualData, [String? indentation]);
 }
 
 /// Default data interpreter for string data.
@@ -457,8 +460,7 @@
   const StringDataInterpreter();
 
   @override
-  String isAsExpected(String actualData, String expectedData) {
-    actualData ??= '';
+  String? isAsExpected(String actualData, String? expectedData) {
     expectedData ??= '';
     if (actualData != expectedData) {
       return "Expected $expectedData, found $actualData";
@@ -472,7 +474,7 @@
   }
 
   @override
-  String getText(String actualData, [String indentation]) {
+  String getText(String actualData, [String? indentation]) {
     return actualData;
   }
 }
@@ -488,7 +490,7 @@
     if (offset > end) {
       sb.write(sourceCode.substring(end, offset));
     }
-    for (String annotation in annotations[offset]) {
+    for (String annotation in annotations[offset]!) {
       sb.write(colorizeAnnotation('/*', annotation, '*/'));
     }
     end = offset;
@@ -508,22 +510,22 @@
     MemberAnnotations<IdValue> expectedMaps,
     CompiledData<T> compiledData,
     DataInterpreter<T> dataInterpreter,
-    {bool filterActualData(IdValue expected, ActualData<T> actualData),
+    {bool filterActualData(IdValue? expected, ActualData<T> actualData)?,
     bool fatalErrors: true,
     bool succinct: false,
-    void onFailure(String message)}) async {
+    required void onFailure(String message)}) async {
   bool hasFailure = false;
   Set<Uri> neededDiffs = new Set<Uri>();
 
-  void checkActualMap(
-      Map<Id, ActualData<T>> actualMap, Map<Id, IdValue> expectedMap, Uri uri) {
+  void checkActualMap(Map<Id, ActualData<T>> actualMap,
+      Map<Id, IdValue>? expectedMap, Uri uri) {
     expectedMap ??= {};
     bool hasLocalFailure = false;
-    actualMap?.forEach((Id id, ActualData<T> actualData) {
+    actualMap.forEach((Id id, ActualData<T> actualData) {
       T actual = actualData.value;
       String actualText = dataInterpreter.getText(actual);
 
-      if (!expectedMap.containsKey(id)) {
+      if (!expectedMap!.containsKey(id)) {
         if (!dataInterpreter.isEmpty(actual)) {
           String actualValueText = IdValue.idToString(id, actualText);
           compiledData.reportError(
@@ -541,8 +543,8 @@
           }
         }
       } else {
-        IdValue expected = expectedMap[id];
-        String unexpectedMessage =
+        IdValue expected = expectedMap[id]!;
+        String? unexpectedMessage =
             dataInterpreter.isAsExpected(actual, expected.value);
         if (unexpectedMessage != null) {
           String actualValueText = IdValue.idToString(id, actualText);
@@ -566,9 +568,7 @@
     });
     if (hasLocalFailure) {
       hasFailure = true;
-      if (uri != null) {
-        neededDiffs.add(uri);
-      }
+      neededDiffs.add(uri);
     }
   }
 
@@ -580,11 +580,11 @@
 
   Set<Id> missingIds = new Set<Id>();
   void checkMissing(
-      Map<Id, IdValue> expectedMap, Map<Id, ActualData<T>> actualMap,
-      [Uri uri]) {
+      Map<Id, IdValue>? expectedMap, Map<Id, ActualData<T>>? actualMap,
+      [Uri? uri]) {
     actualMap ??= {};
     expectedMap?.forEach((Id id, IdValue expected) {
-      if (!actualMap.containsKey(id)) {
+      if (!actualMap!.containsKey(id)) {
         missingIds.add(id);
         String message = 'MISSING $modeName DATA for ${id.descriptor}: '
             'Expected ${colorizeExpected('$expected')}';
@@ -617,9 +617,9 @@
           createDiff: createAnnotationsDiff);
       for (Uri uri in neededDiffs) {
         print('--annotations diff [${uri.pathSegments.last}]-------------');
-        AnnotatedCode annotatedCode = code[uri];
+        AnnotatedCode? annotatedCode = code[uri];
         print(new AnnotatedCode(annotatedCode?.annotatedCode ?? "",
-                annotatedCode?.sourceCode ?? "", annotations[uri])
+                annotatedCode?.sourceCode ?? "", annotations[uri]!)
             .toText());
         print('----------------------------------------------------------');
       }
@@ -640,7 +640,7 @@
     bool verbose,
     bool succinct,
     bool printCode,
-    Map<String, List<String>> skipMap,
+    Map<String, List<String>>? skipMap,
     Uri nullUri});
 
 /// Compute the file: URI of the file located at `path`, where `path` is
@@ -739,12 +739,12 @@
     {List<String> args: const <String>[],
     int shards: 1,
     int shardIndex: 0,
-    void onTest(Uri uri),
-    Uri createUriForFileName(String fileName),
-    void onFailure(String message),
-    RunTestFunction<T> runTest,
-    List<String> skipList,
-    Map<String, List<String>> skipMap,
+    void onTest(Uri uri)?,
+    required Uri createUriForFileName(String fileName),
+    required void onFailure(String message),
+    required RunTestFunction<T> runTest,
+    List<String>? skipList,
+    Map<String, List<String>>? skipMap,
     bool preserveWhitespaceInAnnotations: false,
     bool preserveInfixWhitespaceInAnnotations: false}) async {
   MarkerOptions markerOptions =
@@ -834,7 +834,7 @@
       hasFailures = true;
     } else if (hasMismatches || (forceUpdate && generateAnnotations)) {
       if (generateAnnotations) {
-        DataInterpreter dataInterpreter;
+        DataInterpreter? dataInterpreter;
         Map<String, Map<Uri, Map<Id, ActualData<T>>>> actualData = {};
         results.forEach((String marker, TestResult<T> result) {
           dataInterpreter ??= result.interpreter;
@@ -842,8 +842,10 @@
               actualData[marker] = {};
 
           void addActualData(Uri uri, Map<Id, ActualData<T>> actualData) {
+            // ignore: unnecessary_null_comparison
             assert(uri != null && testData.code.containsKey(uri) ||
                 actualData.isEmpty);
+            // ignore: unnecessary_null_comparison
             if (uri == null || actualData.isEmpty) {
               // TODO(johnniwinther): Avoid collecting data without
               //  invalid uris.
@@ -854,9 +856,9 @@
             actualDataPerId.addAll(actualData);
           }
 
-          result.compiledData.actualMaps.forEach(addActualData);
+          result.compiledData!.actualMaps.forEach(addActualData);
           addActualData(
-              result.compiledData.mainUri, result.compiledData.globalData);
+              result.compiledData!.mainUri, result.compiledData!.globalData);
         });
 
         Map<Uri, List<Annotation>> annotations = computeAnnotationsPerUri(
@@ -864,16 +866,17 @@
             testData.expectedMaps,
             testData.entryPoint,
             actualData,
-            dataInterpreter,
+            dataInterpreter!,
             forceUpdate: forceUpdate);
         annotations.forEach((Uri uri, List<Annotation> annotations) {
+          // ignore: unnecessary_null_comparison
           assert(uri != null, "Annotations without uri: $annotations");
-          AnnotatedCode code = testData.code[uri];
+          AnnotatedCode? code = testData.code[uri];
           assert(code != null,
               "No annotated code for $uri with annotations: $annotations");
           AnnotatedCode generated = new AnnotatedCode(
               code?.annotatedCode ?? "", code?.sourceCode ?? "", annotations);
-          Uri fileUri = testToFileUri[uri];
+          Uri fileUri = testToFileUri[uri]!;
           new File.fromUri(fileUri).writeAsStringSync(generated.toText());
           print('Generated annotations for ${fileUri}');
         });
@@ -893,9 +896,9 @@
 /// Returns `true` if [testName] is marked as skipped in [skipMap] for
 /// the given [configMarker].
 bool skipForConfig(
-    String testName, String configMarker, Map<String, List<String>> skipMap) {
+    String testName, String configMarker, Map<String, List<String>>? skipMap) {
   if (skipMap != null) {
-    List<String> skipList = skipMap[configMarker];
+    List<String>? skipList = skipMap[configMarker];
     if (skipList != null && skipList.contains(testName)) {
       print("Skip: ${testName} for config '${configMarker}'");
       return true;
diff --git a/pkg/_fe_analyzer_shared/lib/src/util/colors.dart b/pkg/_fe_analyzer_shared/lib/src/util/colors.dart
index f4f1b1b..af78689 100644
--- a/pkg/_fe_analyzer_shared/lib/src/util/colors.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/util/colors.dart
@@ -75,7 +75,7 @@
 /// Boolean value caching whether or not we should display ANSI colors.
 ///
 /// If `null`, we haven't decided whether we should display ANSI colors or not.
-bool _enableColors;
+bool? _enableColors;
 
 /// Finds out whether we are displaying ANSI colors.
 ///
@@ -87,6 +87,7 @@
 /// Allows the client to override the decision of whether to disable ANSI
 /// colors.
 void set enableColors(bool value) {
+  // ignore: unnecessary_null_comparison
   assert(value != null);
   _enableColors = value;
 }
@@ -106,7 +107,7 @@
 
 /// Returns whether [sink] supports ANSI escapes or `null` if it could not be
 /// determined.
-bool _supportsAnsiEscapes(sink) {
+bool? _supportsAnsiEscapes(sink) {
   try {
     // ignore: undefined_getter
     return sink.supportsAnsiEscapes;
@@ -132,8 +133,8 @@
 /// Note: do not call this method directly, as it is expensive to
 /// compute. Instead, use [CompilerContext.enableColors].
 bool _computeEnableColors() {
-  bool stderrSupportsColors = _supportsAnsiEscapes(stdout);
-  bool stdoutSupportsColors = _supportsAnsiEscapes(stderr);
+  bool? stderrSupportsColors = _supportsAnsiEscapes(stdout);
+  bool? stdoutSupportsColors = _supportsAnsiEscapes(stderr);
 
   if (stdoutSupportsColors == false) {
     printEnableColorsReason(
diff --git a/pkg/_fe_analyzer_shared/lib/src/util/link.dart b/pkg/_fe_analyzer_shared/lib/src/util/link.dart
index 2474f06..cfbe99f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/util/link.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/util/link.dart
@@ -9,7 +9,7 @@
 
 class Link<T> implements Iterable<T> {
   T get head => throw new StateError("no elements");
-  Link<T> get tail => null;
+  Link<T>? get tail => null;
 
   const Link();
 
@@ -22,16 +22,9 @@
   void printOn(StringBuffer buffer, [separatedBy]) {}
 
   List<T> toList({bool growable: true}) {
-    List<T> result;
-    if (!growable) {
-      result = new List<T>.filled(slowLength(), null);
-    } else {
-      result = <T>[];
-      result.length = slowLength();
-    }
-    int i = 0;
-    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
-      result[i++] = link.head;
+    List<T> result = <T>[];
+    for (Link<T> link = this; !link.isEmpty; link = link.tail!) {
+      result.add(link.head);
     }
     return result;
   }
@@ -43,16 +36,17 @@
 
   /// Invokes `fn` for every item in the linked list and returns the results
   /// in a [List].
-  List<E> mapToList<E>(E fn(T item), {bool growable: true}) {
-    List<E> result;
+  /// TODO(scheglov) Rewrite to `List<E>`, or remove.
+  List<E?> mapToList<E>(E fn(T item), {bool growable: true}) {
+    List<E?> result;
     if (!growable) {
-      result = new List<E>.filled(slowLength(), null);
+      result = new List<E?>.filled(slowLength(), null);
     } else {
-      result = <E>[];
+      result = <E?>[];
       result.length = slowLength();
     }
     int i = 0;
-    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
+    for (Link<T> link = this; !link.isEmpty; link = link.tail!) {
       result[i++] = fn(link.head);
     }
     return result;
@@ -65,7 +59,7 @@
 
   Link<T> reversePrependAll(Link<T> from) {
     if (from.isEmpty) return this;
-    return this.prepend(from.head).reversePrependAll(from.tail);
+    return this.prepend(from.head).reversePrependAll(from.tail!);
   }
 
   Link<T> skip(int n) {
@@ -91,8 +85,8 @@
   int slowLength() => 0;
 
   // TODO(ahe): Remove this method?
-  bool contains(Object element) {
-    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
+  bool contains(Object? element) {
+    for (Link<T> link = this; !link.isEmpty; link = link.tail!) {
       if (link.head == element) return true;
     }
     return false;
@@ -101,7 +95,7 @@
   // TODO(ahe): Remove this method?
   T get single {
     if (isEmpty) throw new StateError('No elements');
-    if (!tail.isEmpty) throw new StateError('More than one element');
+    if (!tail!.isEmpty) throw new StateError('More than one element');
     return head;
   }
 
@@ -115,7 +109,7 @@
   ///
   /// Returns true for the empty list.
   bool every(bool f(T e)) {
-    for (Link<T> link = this; !link.isEmpty; link = link.tail) {
+    for (Link<T> link = this; !link.isEmpty; link = link.tail!) {
       if (!f(link.head)) return false;
     }
     return true;
@@ -128,18 +122,18 @@
   Iterable<T> cast<T>() => _unsupported('cast');
   T elementAt(int i) => _unsupported('elementAt');
   Iterable<K> expand<K>(Iterable<K> f(T e)) => _unsupported('expand');
-  T firstWhere(bool f(T e), {T orElse()}) => _unsupported('firstWhere');
+  T firstWhere(bool f(T e), {T orElse()?}) => _unsupported('firstWhere');
   K fold<K>(K initialValue, K combine(K value, T element)) {
     return _unsupported('fold');
   }
 
   Iterable<T> followedBy(Iterable<T> other) => _unsupported('followedBy');
   T get last => _unsupported('get:last');
-  T lastWhere(bool f(T e), {T orElse()}) => _unsupported('lastWhere');
+  T lastWhere(bool f(T e), {T orElse()?}) => _unsupported('lastWhere');
   String join([separator = '']) => _unsupported('join');
   T reduce(T combine(T a, T b)) => _unsupported('reduce');
   Iterable<T> retype<T>() => _unsupported('retype');
-  T singleWhere(bool f(T e), {T orElse()}) => _unsupported('singleWhere');
+  T singleWhere(bool f(T e), {T orElse()?}) => _unsupported('singleWhere');
   Iterable<T> skipWhile(bool f(T e)) => _unsupported('skipWhile');
   Iterable<T> take(int n) => _unsupported('take');
   Iterable<T> takeWhile(bool f(T e)) => _unsupported('takeWhile');
@@ -170,10 +164,10 @@
   T get first;
 
   /// Returns the number of elements in the list being built.
-  final int length;
+  int get length;
 
   /// Returns `true` if the list being built is empty.
-  final bool isEmpty;
+  bool get isEmpty;
 
   /// Removes all added elements and resets the builder.
   void clear();
diff --git a/pkg/_fe_analyzer_shared/lib/src/util/link_implementation.dart b/pkg/_fe_analyzer_shared/lib/src/util/link_implementation.dart
index 7fced1a..70f86ec 100644
--- a/pkg/_fe_analyzer_shared/lib/src/util/link_implementation.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/util/link_implementation.dart
@@ -9,12 +9,12 @@
 import 'link.dart' show Link, LinkBuilder;
 
 class LinkIterator<T> implements Iterator<T> {
-  T _current;
+  T? _current;
   Link<T> _link;
 
   LinkIterator(this._link);
 
-  T get current => _current;
+  T get current => _current!;
 
   bool moveNext() {
     if (_link.isEmpty) {
@@ -22,7 +22,7 @@
       return false;
     }
     _current = _link.head;
-    _link = _link.tail;
+    _link = _link.tail!;
     return true;
   }
 }
@@ -32,11 +32,11 @@
 class MappedLinkIterator<S, T> extends Iterator<T> {
   Transformation<S, T> _transformation;
   Link<S> _link;
-  T _current;
+  T? _current;
 
   MappedLinkIterator(this._link, this._transformation);
 
-  T get current => _current;
+  T get current => _current!;
 
   bool moveNext() {
     if (_link.isEmpty) {
@@ -44,7 +44,7 @@
       return false;
     }
     _current = _transformation(_link.head);
-    _link = _link.tail;
+    _link = _link.tail!;
     return true;
   }
 }
@@ -64,7 +64,7 @@
   final T head;
   Link<T> tail;
 
-  LinkEntry(this.head, [Link<T> tail]) : tail = tail ?? const Link<Null>();
+  LinkEntry(this.head, [Link<T>? tail]) : tail = tail ?? const Link<Never>();
 
   Link<T> prepend(T element) {
     // TODO(ahe): Use new Link<T>, but this cost 8% performance on VM.
@@ -74,7 +74,7 @@
   void printOn(StringBuffer buffer, [separatedBy]) {
     buffer.write(head);
     if (separatedBy == null) separatedBy = '';
-    for (Link<T> link = tail; link.isNotEmpty; link = link.tail) {
+    for (Link<T> link = tail; link.isNotEmpty; link = link.tail!) {
       buffer.write(separatedBy);
       buffer.write(link.head);
     }
@@ -91,7 +91,7 @@
   @override
   Link<T> reverse(Link<T> tail) {
     Link<T> result = tail;
-    for (Link<T> link = this; link.isNotEmpty; link = link.tail) {
+    for (Link<T> link = this; link.isNotEmpty; link = link.tail!) {
       result = result.prepend(link.head);
     }
     return result;
@@ -99,7 +99,7 @@
 
   Link<T> reversePrependAll(Link<T> from) {
     Link<T> result;
-    for (result = this; from.isNotEmpty; from = from.tail) {
+    for (result = this; from.isNotEmpty; from = from.tail!) {
       result = result.prepend(from.head);
     }
     return result;
@@ -111,7 +111,7 @@
       if (link.isEmpty) {
         throw new RangeError('Index $n out of range');
       }
-      link = link.tail;
+      link = link.tail!;
     }
     return link;
   }
@@ -120,7 +120,7 @@
   bool get isNotEmpty => true;
 
   void forEach(void f(T element)) {
-    for (Link<T> link = this; link.isNotEmpty; link = link.tail) {
+    for (Link<T> link = this; link.isNotEmpty; link = link.tail!) {
       f(link.head);
     }
   }
@@ -128,21 +128,22 @@
   bool operator ==(other) {
     if (other is! Link<T>) return false;
     Link<T> myElements = this;
-    while (myElements.isNotEmpty && other.isNotEmpty) {
-      if (myElements.head != other.head) {
+    Link<T> otherElements = other;
+    while (myElements.isNotEmpty && otherElements.isNotEmpty) {
+      if (myElements.head != otherElements.head) {
         return false;
       }
-      myElements = myElements.tail;
-      other = other.tail;
+      myElements = myElements.tail!;
+      otherElements = otherElements.tail!;
     }
-    return myElements.isEmpty && other.isEmpty;
+    return myElements.isEmpty && otherElements.isEmpty;
   }
 
   int get hashCode => throw new UnsupportedError('LinkEntry.hashCode');
 
   int slowLength() {
     int length = 0;
-    for (Link<T> current = this; current.isNotEmpty; current = current.tail) {
+    for (Link<T> current = this; current.isNotEmpty; current = current.tail!) {
       ++length;
     }
     return length;
@@ -150,8 +151,8 @@
 }
 
 class LinkBuilderImplementation<T> implements LinkBuilder<T> {
-  LinkEntry<T> head = null;
-  LinkEntry<T> lastLink = null;
+  LinkEntry<T>? head = null;
+  LinkEntry<T>? lastLink = null;
   int length = 0;
 
   LinkBuilderImplementation();
@@ -159,8 +160,8 @@
   @override
   Link<T> toLink(Link<T> tail) {
     if (head == null) return tail;
-    lastLink.tail = tail;
-    Link<T> link = head;
+    lastLink!.tail = tail;
+    Link<T> link = head!;
     lastLink = null;
     head = null;
     length = 0;
@@ -168,14 +169,13 @@
   }
 
   List<T> toList() {
-    if (length == 0) return new List<T>.filled(0, null);
-    List<T> list = new List<T>.filled(length, null);
-    int index = 0;
-    Link<T> link = head;
+    if (length == 0) return <T>[];
+
+    List<T> list = <T>[];
+    Link<T> link = head!;
     while (link.isNotEmpty) {
-      list[index] = link.head;
-      link = link.tail;
-      index++;
+      list.add(link.head);
+      link = link.tail!;
     }
     lastLink = null;
     head = null;
@@ -189,7 +189,7 @@
     if (head == null) {
       head = entry;
     } else {
-      lastLink.tail = entry;
+      lastLink!.tail = entry;
     }
     lastLink = entry;
     return entry;
@@ -199,7 +199,7 @@
 
   T get first {
     if (head != null) {
-      return head.head;
+      return head!.head;
     }
     throw new StateError("no elements");
   }
diff --git a/pkg/_fe_analyzer_shared/pubspec.yaml b/pkg/_fe_analyzer_shared/pubspec.yaml
index 951d2a4..4252300 100644
--- a/pkg/_fe_analyzer_shared/pubspec.yaml
+++ b/pkg/_fe_analyzer_shared/pubspec.yaml
@@ -4,7 +4,7 @@
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/_fe_analyzer_shared
 
 environment:
-  sdk: '>=2.9.0 <3.0.0'
+  sdk: '>=2.12.0-0 <3.0.0'
 dependencies:
   meta: ^1.0.2
 dev_dependencies:
diff --git a/pkg/_fe_analyzer_shared/test/annotated_code_helper_test.dart b/pkg/_fe_analyzer_shared/test/annotated_code_helper_test.dart
index e293175..9fb1558 100644
--- a/pkg/_fe_analyzer_shared/test/annotated_code_helper_test.dart
+++ b/pkg/_fe_analyzer_shared/test/annotated_code_helper_test.dart
@@ -53,7 +53,7 @@
         const StringDataInterpreter());
 
     annotationsPerUri.forEach((Uri uri, List<Annotation> annotations) {
-      AnnotatedCode original = testData.code[uri];
+      AnnotatedCode original = testData.code[uri]!;
       AnnotatedCode generated = new AnnotatedCode(
           original.annotatedCode, original.sourceCode, annotations);
       expectStringEquals(generated.annotatedCode, generated.toText());
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
index 6b7be5d..70f50e4 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
@@ -7,12 +7,11 @@
 /// AST nodes and then feed them to [Harness.run] to run them through flow
 /// analysis testing.
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
-import 'package:meta/meta.dart';
 import 'package:test/test.dart';
 
 const Expression nullLiteral = const _NullLiteral();
 
-Statement assert_(Expression condition, [Expression message]) =>
+Statement assert_(Expression condition, [Expression? message]) =>
     new _Assert(condition, message);
 
 Statement block(List<Statement> statements) => new _Block(statements);
@@ -37,7 +36,7 @@
     SwitchCase._(hasLabel, body);
 
 CatchClause catch_(
-        {Var exception, Var stackTrace, @required List<Statement> body}) =>
+        {Var? exception, Var? stackTrace, required List<Statement> body}) =>
     CatchClause._(body, exception, stackTrace);
 
 /// Creates a pseudo-statement whose function is to verify that flow analysis
@@ -51,7 +50,7 @@
 
 /// Creates a pseudo-statement whose function is to verify that flow analysis
 /// considers [variable]'s assigned state to be promoted to [expectedTypeStr].
-Statement checkPromoted(Var variable, String expectedTypeStr) =>
+Statement checkPromoted(Var variable, String? expectedTypeStr) =>
     new _CheckPromoted(variable, expectedTypeStr);
 
 /// Creates a pseudo-statement whose function is to verify that flow analysis
@@ -68,7 +67,7 @@
 Statement continue_(BranchTargetPlaceholder branchTargetPlaceholder) =>
     new _Continue(branchTargetPlaceholder);
 
-Statement declare(Var variable, {@required bool initialized}) =>
+Statement declare(Var variable, {required bool initialized}) =>
     new _Declare(variable, initialized);
 
 Statement do_(List<Statement> body, Expression condition) =>
@@ -82,8 +81,8 @@
 /// Creates a conventional `for` statement.  Optional boolean [forCollection]
 /// indicates that this `for` statement is actually a collection element, so
 /// `null` should be passed to [for_bodyBegin].
-Statement for_(Statement initializer, Expression condition, Expression updater,
-        List<Statement> body,
+Statement for_(Statement? initializer, Expression? condition,
+        Expression? updater, List<Statement> body,
         {bool forCollection = false}) =>
     new _For(initializer, condition, updater, body, forCollection);
 
@@ -107,6 +106,7 @@
 ///     }
 Statement forEachWithVariableDecl(
     Var variable, Expression iterable, List<Statement> body) {
+  // ignore: unnecessary_null_comparison
   assert(variable != null);
   return new _ForEach(variable, iterable, body, true);
 }
@@ -121,12 +121,13 @@
 ///     }
 Statement forEachWithVariableSet(
     Var variable, Expression iterable, List<Statement> body) {
+  // ignore: unnecessary_null_comparison
   assert(variable != null);
   return new _ForEach(variable, iterable, body, false);
 }
 
 Statement if_(Expression condition, List<Statement> ifTrue,
-        [List<Statement> ifFalse]) =>
+        [List<Statement>? ifFalse]) =>
     new _If(condition, ifTrue, ifFalse);
 
 Statement labeled(Statement body) => new _LabeledStatement(body);
@@ -136,7 +137,7 @@
 Statement return_() => new _Return();
 
 Statement switch_(Expression expression, List<SwitchCase> cases,
-        {@required bool isExhaustive}) =>
+        {required bool isExhaustive}) =>
     new _Switch(expression, cases, isExhaustive);
 
 Statement tryCatch(List<Statement> body, List<CatchClause> catches) =>
@@ -151,26 +152,26 @@
 /// Placeholder used by [branchTarget] to tie `break` and `continue` statements
 /// to their branch targets.
 class BranchTargetPlaceholder {
-  Statement _target;
+  late Statement _target;
 
-  /*late*/ BranchTargetPlaceholder._();
+  BranchTargetPlaceholder._();
 }
 
 /// Representation of a single catch clause in a try/catch statement.  Use
 /// [catch_] to create instances of this class.
 class CatchClause implements _Visitable<void> {
   final List<Statement> _body;
-  final Var _exception;
-  final Var _stackTrace;
+  final Var? _exception;
+  final Var? _stackTrace;
 
   CatchClause._(this._body, this._exception, this._stackTrace);
 
   String toString() {
     String initialPart;
     if (_stackTrace != null) {
-      initialPart = 'catch (${_exception.name}, ${_stackTrace.name})';
+      initialPart = 'catch (${_exception!.name}, ${_stackTrace!.name})';
     } else if (_exception != null) {
-      initialPart = 'catch (${_exception.name})';
+      initialPart = 'catch (${_exception!.name})';
     } else {
       initialPart = 'on ...';
     }
@@ -365,7 +366,7 @@
 
   final Map<String, Type> _factorResults = Map.of(_coreFactors);
 
-  Node _currentSwitch;
+  Node? _currentSwitch;
 
   /// Updates the harness so that when a [factor] query is invoked on types
   /// [from] and [what], [result] will be returned.
@@ -438,7 +439,7 @@
   }
 
   @override
-  Type tryPromoteToType(Type to, Type from) {
+  Type? tryPromoteToType(Type to, Type from) {
     if (isSubtypeOf(to, from)) {
       return to;
     } else {
@@ -517,7 +518,7 @@
 
   void _visit(
       Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.switchStatement_beginCase(_hasLabel, h._currentSwitch);
+    flow.switchStatement_beginCase(_hasLabel, h._currentSwitch!);
     _body._visit(h, flow);
   }
 }
@@ -584,7 +585,7 @@
 
 class _Assert extends Statement {
   final Expression condition;
-  final Expression message;
+  final Expression? message;
 
   _Assert(this.condition, this.message) : super._();
 
@@ -662,6 +663,7 @@
   @override
   void _visit(
       Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+    // ignore: unnecessary_null_comparison
     assert(branchTargetPlaceholder._target != null);
     flow.handleBreak(branchTargetPlaceholder._target);
   }
@@ -691,7 +693,7 @@
 
 class _CheckPromoted extends Statement {
   final Var variable;
-  final String expectedTypeStr;
+  final String? expectedTypeStr;
 
   _CheckPromoted(this.variable, this.expectedTypeStr) : super._();
 
@@ -713,7 +715,7 @@
     if (expectedTypeStr == null) {
       expect(promotedType, isNull);
     } else {
-      expect(promotedType.type, expectedTypeStr);
+      expect(promotedType?.type, expectedTypeStr);
     }
   }
 }
@@ -802,6 +804,7 @@
   @override
   void _visit(
       Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+    // ignore: unnecessary_null_comparison
     assert(branchTargetPlaceholder._target != null);
     flow.handleContinue(branchTargetPlaceholder._target);
   }
@@ -902,9 +905,9 @@
 }
 
 class _For extends Statement {
-  final Statement initializer;
-  final Expression condition;
-  final Expression updater;
+  final Statement? initializer;
+  final Expression? condition;
+  final Expression? updater;
   final List<Statement> body;
   final bool forCollection;
 
@@ -957,7 +960,7 @@
 }
 
 class _ForEach extends Statement {
-  final Var variable;
+  final Var? variable;
   final Expression iterable;
   final List<Statement> body;
   final bool declaresVariable;
@@ -973,7 +976,7 @@
     } else if (declaresVariable) {
       declarationPart = variable.toString();
     } else {
-      declarationPart = variable.name;
+      declarationPart = variable!.name;
     }
     return 'for ($declarationPart in $iterable) ${block(body)}';
   }
@@ -983,9 +986,9 @@
     iterable._preVisit(assignedVariables);
     if (variable != null) {
       if (declaresVariable) {
-        assignedVariables.declare(variable);
+        assignedVariables.declare(variable!);
       } else {
-        assignedVariables.write(variable);
+        assignedVariables.write(variable!);
       }
     }
     assignedVariables.beginNode();
@@ -1006,14 +1009,14 @@
 class _If extends Statement {
   final Expression condition;
   final List<Statement> ifTrue;
-  final List<Statement> ifFalse;
+  final List<Statement>? ifFalse;
 
   _If(this.condition, this.ifTrue, this.ifFalse) : super._();
 
   @override
   String toString() =>
       'if ($condition) ${block(ifTrue)}' +
-      (ifFalse == null ? '' : 'else ${block(ifFalse)}');
+      (ifFalse == null ? '' : 'else ${block(ifFalse!)}');
 
   @override
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -1032,7 +1035,7 @@
       flow.ifStatement_end(false);
     } else {
       flow.ifStatement_elseBegin();
-      ifFalse._visit(h, flow);
+      ifFalse!._visit(h, flow);
       flow.ifStatement_end(true);
     }
   }
@@ -1138,7 +1141,7 @@
   final Expression rhs;
   final bool isAnd;
 
-  _Logical(this.lhs, this.rhs, {@required this.isAnd});
+  _Logical(this.lhs, this.rhs, {required this.isAnd});
 
   @override
   String toString() => '$lhs ${isAnd ? '&&' : '||'} $rhs';
@@ -1418,7 +1421,7 @@
   @override
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
     assignedVariables.beginNode();
-    condition?._preVisit(assignedVariables);
+    condition._preVisit(assignedVariables);
     body._preVisit(assignedVariables);
     assignedVariables.endNode(this);
   }
@@ -1427,7 +1430,7 @@
   void _visit(
       Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
     flow.whileStatement_conditionBegin(this);
-    condition?._visit(h, flow);
+    condition._visit(h, flow);
     flow.whileStatement_bodyBegin(this, condition);
     body._visit(h, flow);
     flow.whileStatement_end();
@@ -1435,9 +1438,9 @@
 }
 
 class _WrappedExpression extends Expression {
-  final Statement before;
+  final Statement? before;
   final Expression expr;
-  final Statement after;
+  final Statement? after;
 
   _WrappedExpression(this.before, this.expr, this.after);
 
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 7d3a04f..35f7d10 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
@@ -968,7 +968,7 @@
     });
 
     void _checkIs(String declaredType, String tryPromoteType,
-        String expectedPromotedTypeThen, String expectedPromotedTypeElse,
+        String? expectedPromotedTypeThen, String? expectedPromotedTypeElse,
         {bool inverted = false}) {
       var h = Harness();
       var x = Var('x', declaredType);
@@ -2016,21 +2016,21 @@
     group('unsplitTo', () {
       test('no change', () {
         var s1 = FlowModel<Var, Type>(Reachability.initial.split());
-        var result = s1.unsplitTo(s1.reachable.parent);
+        var result = s1.unsplitTo(s1.reachable.parent!);
         expect(result, same(s1));
       });
 
       test('unsplit once, reachable', () {
         var s1 = FlowModel<Var, Type>(Reachability.initial.split());
         var s2 = s1.split();
-        var result = s2.unsplitTo(s1.reachable.parent);
+        var result = s2.unsplitTo(s1.reachable.parent!);
         expect(result.reachable, same(s1.reachable));
       });
 
       test('unsplit once, unreachable', () {
         var s1 = FlowModel<Var, Type>(Reachability.initial.split());
         var s2 = s1.split().setUnreachable();
-        var result = s2.unsplitTo(s1.reachable.parent);
+        var result = s2.unsplitTo(s1.reachable.parent!);
         expect(result.reachable.locallyReachable, false);
         expect(result.reachable.parent, same(s1.reachable.parent));
       });
@@ -2039,7 +2039,7 @@
         var s1 = FlowModel<Var, Type>(Reachability.initial.split());
         var s2 = s1.split();
         var s3 = s2.split();
-        var result = s3.unsplitTo(s1.reachable.parent);
+        var result = s3.unsplitTo(s1.reachable.parent!);
         expect(result.reachable, same(s1.reachable));
       });
 
@@ -2047,7 +2047,7 @@
         var s1 = FlowModel<Var, Type>(Reachability.initial.split());
         var s2 = s1.split();
         var s3 = s2.split().setUnreachable();
-        var result = s3.unsplitTo(s1.reachable.parent);
+        var result = s3.unsplitTo(s1.reachable.parent!);
         expect(result.reachable.locallyReachable, false);
         expect(result.reachable.parent, same(s1.reachable.parent));
       });
@@ -2056,7 +2056,7 @@
         var s1 = FlowModel<Var, Type>(Reachability.initial.split());
         var s2 = s1.split().setUnreachable();
         var s3 = s2.split();
-        var result = s3.unsplitTo(s1.reachable.parent);
+        var result = s3.unsplitTo(s1.reachable.parent!);
         expect(result.reachable.locallyReachable, false);
         expect(result.reachable.parent, same(s1.reachable.parent));
       });
@@ -2409,7 +2409,7 @@
 
       group('Multiple candidate types of interest', () {
         group('; choose most specific', () {
-          Harness h;
+          late Harness h;
 
           setUp(() {
             h = Harness();
@@ -2782,8 +2782,8 @@
       });
 
       test('promotion', () {
-        void _check(String thisType, String otherType, bool unsafe,
-            List<String> expectedChain) {
+        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);
@@ -2798,7 +2798,7 @@
             expect(result.variableInfo, contains(x));
             expect(result.infoFor(x).promotedTypes, isNull);
           } else {
-            expect(result.infoFor(x).promotedTypes.map((t) => t.type).toList(),
+            expect(result.infoFor(x).promotedTypes!.map((t) => t.type).toList(),
                 expectedChain);
           }
         }
@@ -2820,7 +2820,7 @@
       test('promotion chains', () {
         // Verify that the given promotion chain matches the expected list of
         // strings.
-        void _checkChain(List<Type> chain, List<String> expected) {
+        void _checkChain(List<Type>? chain, List<String> expected) {
           var strings = (chain ?? <Type>[]).map((t) => t.type).toList();
           expect(strings, expected);
         }
@@ -3072,8 +3072,8 @@
     var stringType = Type('String');
     const emptyMap = const <Var, VariableModel<Var, Type>>{};
 
-    VariableModel<Var, Type> model(List<Type> promotionChain,
-            {List<Type> typesOfInterest, bool assigned = false}) =>
+    VariableModel<Var, Type> model(List<Type>? promotionChain,
+            {List<Type>? typesOfInterest, bool assigned = false}) =>
         VariableModel<Var, Type>(
           promotionChain,
           typesOfInterest ?? promotionChain ?? [],
@@ -3257,7 +3257,7 @@
     var stringType = Type('String');
     const emptyMap = const <Var, VariableModel<Var, Type>>{};
 
-    VariableModel<Var, Type> varModel(List<Type> promotionChain,
+    VariableModel<Var, Type> varModel(List<Type>? promotionChain,
             {bool assigned = false}) =>
         VariableModel<Var, Type>(
           promotionChain,
@@ -3269,7 +3269,8 @@
 
     test('first is null', () {
       var h = Harness();
-      var s1 = FlowModel.withInfo(Reachability.initial.split(), {});
+      var s1 = FlowModel.withInfo(
+          Reachability.initial.split(), emptyMap);
       var result = FlowModel.merge(h, null, s1, emptyMap);
       expect(result.reachable, same(Reachability.initial));
     });
@@ -3278,7 +3279,7 @@
       var h = Harness();
       var splitPoint = Reachability.initial.split();
       var afterSplit = splitPoint.split();
-      var s1 = FlowModel.withInfo(afterSplit, {});
+      var s1 = FlowModel.withInfo(afterSplit, emptyMap);
       var result = FlowModel.merge(h, s1, null, emptyMap);
       expect(result.reachable, same(splitPoint));
     });
@@ -3295,7 +3296,7 @@
       });
       var result = FlowModel.merge(h, s1, s2, emptyMap);
       expect(result.reachable, same(splitPoint));
-      expect(result.variableInfo[x].promotedTypes, isNull);
+      expect(result.variableInfo[x]!.promotedTypes, isNull);
     });
 
     test('first is unreachable', () {
@@ -3341,7 +3342,7 @@
       var result = FlowModel.merge(h, s1, s2, emptyMap);
       expect(result.reachable.locallyReachable, false);
       expect(result.reachable.parent, same(splitPoint.parent));
-      expect(result.variableInfo[x].promotedTypes, isNull);
+      expect(result.variableInfo[x]!.promotedTypes, isNull);
     });
   });
 
@@ -3362,7 +3363,7 @@
       var m2 = FlowModel.withInfo(Reachability.initial, {
         x: model([stringType])
       });
-      expect(m1.inheritTested(h, m2).variableInfo[x].tested,
+      expect(m1.inheritTested(h, m2).variableInfo[x]!.tested,
           _matchOfInterestSet(['int', 'String']));
     });
 
@@ -3413,7 +3414,7 @@
       'interest set $expectedTypes');
 }
 
-Matcher _matchPromotionChain(List<String> expectedTypes) {
+Matcher _matchPromotionChain(List<String>? expectedTypes) {
   if (expectedTypes == null) return isNull;
   return predicate(
       (List<Type> x) =>
@@ -3422,11 +3423,16 @@
 }
 
 Matcher _matchVariableModel(
-    {Object chain = anything,
-    Object ofInterest = anything,
-    Object assigned = anything,
-    Object unassigned = anything,
-    Object writeCaptured = anything}) {
+    {Object? chain,
+    Object? ofInterest,
+    Object? assigned,
+    Object? unassigned,
+    Object? writeCaptured}) {
+  chain ??= anything;
+  ofInterest ??= anything;
+  assigned ??= anything;
+  unassigned ??= anything;
+  writeCaptured ??= anything;
   Matcher chainMatcher =
       chain is List<String> ? _matchPromotionChain(chain) : wrapMatcher(chain);
   Matcher ofInterestMatcher = ofInterest is List<String>
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/final_initializer.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/final_initializer.dart
new file mode 100644
index 0000000..e2221c4
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/final_initializer.dart
@@ -0,0 +1,36 @@
+// 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.
+
+// This test checks that final variables aren't promoted to a type of interest
+// based on their initializer, but non-final variables are.
+
+nonFinalPromotesWhenInitializerNonNullable(int i) {
+  num? n = i;
+  /*num*/ n;
+}
+
+nonFinalDoesNotPromoteWhenInitializerNullable(int? i) {
+  num? n = i;
+  n;
+}
+
+finalDoesNotPromote(int i) {
+  final num? n = i;
+  n;
+}
+
+lateNonFinalPromotesWhenInitializerNonNullable(int i) {
+  late num? n = i;
+  /*num*/ n;
+}
+
+lateNonFinalDoesNotPromoteWhenInitializerNullable(int? i) {
+  late num? n = i;
+  n;
+}
+
+lateFinalDoesNotPromote(int i) {
+  late final num? n = i;
+  n;
+}
diff --git a/pkg/_fe_analyzer_shared/test/id_generation_test.dart b/pkg/_fe_analyzer_shared/test/id_generation_test.dart
index 0f19b23..56abad3 100644
--- a/pkg/_fe_analyzer_shared/test/id_generation_test.dart
+++ b/pkg/_fe_analyzer_shared/test/id_generation_test.dart
@@ -467,7 +467,7 @@
 void testString(
   String text, {
   Map<String, Map<Id, String>> actualData: const {},
-  String expectedResult,
+  String? expectedResult,
   int classOffset: 0,
   int memberOffset: 0,
 }) {
@@ -487,7 +487,7 @@
 void testFeatures(
   String text, {
   Map<String, Map<Id, String>> actualData: const {},
-  String expectedResult,
+  String? expectedResult,
   int classOffset: 0,
   int memberOffset: 0,
 }) {
@@ -507,7 +507,7 @@
 
 void testGeneral<T>(DataInterpreter<T> dataInterpreter, String text,
     {Map<String, Map<Id, T>> actualData: const {},
-    String expectedResult,
+    String? expectedResult,
     int classOffset: 0,
     int memberOffset: 0}) {
   expectedResult ??= text;
@@ -517,7 +517,10 @@
   for (String marker in markers) {
     expectedMaps[marker] = new MemberAnnotations<IdValue>();
   }
-  computeExpectedMap(mainUri, mainUri.path, code, expectedMaps);
+  computeExpectedMap(mainUri, mainUri.path, code, expectedMaps,
+      onFailure: (String message) {
+    throw message;
+  });
 
   Map<String, Map<Uri, Map<Id, ActualData<T>>>> actualAnnotations = {};
   actualData.forEach((String marker, Map<Id, T> data) {
@@ -531,6 +534,8 @@
         offset = memberOffset;
       } else if (id is ClassId) {
         offset = classOffset;
+      } else {
+        offset = 0;
       }
       actualData[id] = new ActualData<T>(id, value, mainUri, offset, text);
     });
@@ -543,10 +548,11 @@
       actualAnnotations,
       dataInterpreter);
   AnnotatedCode generated = new AnnotatedCode(
-      code.annotatedCode, code.sourceCode, annotations[mainUri]);
+      code.annotatedCode, code.sourceCode, annotations[mainUri]!);
   String actualResult = generated.toText();
   if (expectedResult != actualResult) {
     print("Unexpected result for '$text'"
+        // ignore: unnecessary_null_comparison
         "${actualData != null ? ' with actualData=$actualData' : ''}");
     print('---expected-------------------------------------------------------');
     print(expectedResult);
diff --git a/pkg/_fe_analyzer_shared/test/sdk/allowed_experiments_test.dart b/pkg/_fe_analyzer_shared/test/sdk/allowed_experiments_test.dart
index ad70c28..255e072 100644
--- a/pkg/_fe_analyzer_shared/test/sdk/allowed_experiments_test.dart
+++ b/pkg/_fe_analyzer_shared/test/sdk/allowed_experiments_test.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:_fe_analyzer_shared/src/sdk/allowed_experiments.dart';
-import 'package:meta/meta.dart';
 import 'package:test/test.dart';
 
 main() {
@@ -159,9 +158,9 @@
   group('valid', () {
     void assertExperiments(
       AllowedExperiments experiments, {
-      @required List<String> sdkDefaultExperiments,
-      @required Map<String, List<String>> sdkLibraryExperiments,
-      @required Map<String, List<String>> packageExperiments,
+      required List<String> sdkDefaultExperiments,
+      required Map<String, List<String>> sdkLibraryExperiments,
+      required Map<String, List<String>> packageExperiments,
     }) {
       expect(experiments.sdkDefaultExperiments, sdkDefaultExperiments);
       expect(experiments.sdkLibraryExperiments, sdkLibraryExperiments);
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
index ff55c14..251eafe 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
@@ -27,7 +27,7 @@
 const jsonEncoder = JsonEncoder.withIndent('    ');
 
 /// A special text edit with an additional change annotation.
-///  @since 3.16.0 - proposed state.
+///  @since 3.16.0.
 class AnnotatedTextEdit implements TextEdit, ToJsonable {
   static const jsonHandler =
       LspJsonHandler(AnnotatedTextEdit.canParse, AnnotatedTextEdit.fromJson);
@@ -1551,7 +1551,7 @@
 }
 
 /// Additional information that describes document changes.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class ChangeAnnotation implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(ChangeAnnotation.canParse, ChangeAnnotation.fromJson);
@@ -1701,7 +1701,7 @@
   final dynamic experimental;
 
   /// General client capabilities.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final ClientCapabilitiesGeneral general;
 
   /// Text document specific client capabilities.
@@ -2026,11 +2026,11 @@
   }
 
   /// Client capabilities specific to the client's markdown parser.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final MarkdownClientCapabilities markdown;
 
   /// Client capabilities specific to regular expressions.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final RegularExpressionsClientCapabilities regularExpressions;
 
   Map<String, dynamic> toJson() {
@@ -2119,11 +2119,11 @@
   }
 
   /// Client capabilities for the show document request.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final ShowDocumentClientCapabilities showDocument;
 
   /// Capabilities specific to the showMessage request
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final ShowMessageRequestClientCapabilities showMessage;
 
   /// Whether client supports handling progress notifications. If set servers
@@ -2281,7 +2281,7 @@
   final bool applyEdit;
 
   /// Capabilities specific to the code lens requests scoped to the workspace.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final CodeLensWorkspaceClientCapabilities codeLens;
 
   /// The client supports `workspace/configuration` requests.
@@ -2300,12 +2300,12 @@
   final ExecuteCommandClientCapabilities executeCommand;
 
   /// The client has support for file requests/notifications.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final ClientCapabilitiesFileOperations fileOperations;
 
   /// Capabilities specific to the semantic token requests scoped to the
   /// workspace.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final SemanticTokensWorkspaceClientCapabilities semanticTokens;
 
   /// Capabilities specific to the `workspace/symbol` request.
@@ -2586,7 +2586,7 @@
 
   /// A data entry field that is preserved on a code action between a
   /// `textDocument/codeAction` and a `codeAction/resolve` request.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final dynamic data;
 
   /// The diagnostics that this code action resolves.
@@ -2833,11 +2833,11 @@
 
   /// Whether code action supports the `data` property which is preserved
   /// between a `textDocument/codeAction` and a `codeAction/resolve` request.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final bool dataSupport;
 
   /// Whether code action supports the `disabled` property.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final bool disabledSupport;
 
   /// Whether code action supports dynamic registration.
@@ -2847,7 +2847,7 @@
   /// operations returned via the `CodeAction#edit` property by for example
   /// presenting the workspace edit in the user interface and asking for
   /// confirmation.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final bool honorsChangeAnnotations;
 
   /// Whether code action supports the `isPreferred` property.
@@ -2856,7 +2856,7 @@
 
   /// Whether the client supports resolving additional code action properties
   /// via a separate `codeAction/resolve` request.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final CodeActionClientCapabilitiesResolveSupport resolveSupport;
 
   Map<String, dynamic> toJson() {
@@ -3951,7 +3951,7 @@
 }
 
 /// Structure to capture a description for an error code.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class CodeDescription implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(CodeDescription.canParse, CodeDescription.fromJson);
@@ -5470,13 +5470,13 @@
 
   /// Client supports insert replace edit to control different behavior if a
   /// completion item is inserted in the text or should replace text.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final bool insertReplaceSupport;
 
   /// The client supports the `insertTextMode` property on a completion item to
   /// override the whitespace handling mode as defined by the client (see
   /// `insertTextMode`).
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final CompletionClientCapabilitiesInsertTextModeSupport insertTextModeSupport;
 
   /// Client supports the preselect property on a completion item.
@@ -5485,7 +5485,7 @@
   /// Indicates which properties a client can resolve lazily on a completion
   /// item. Before version 3.16.0 only the predefined properties `documentation`
   /// and `details` could be resolved lazily.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final CompletionClientCapabilitiesResolveSupport resolveSupport;
 
   /// Client supports snippets as insert text.
@@ -6235,7 +6235,7 @@
   /// How whitespace and indentation is handled during completion item
   /// insertion. If not provided the client's default value depends on the
   /// `textDocument.completion.insertTextMode` client capability.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final InsertTextMode insertTextMode;
 
   /// The kind of this completion item. Based of the kind an icon is chosen by
@@ -6281,7 +6281,7 @@
   /// *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range
   /// must be a prefix of the edit's replace range, that means it must be
   /// contained and starting at the same position.
-  ///  @since 3.16.0 additional type `InsertReplaceEdit` - proposed state
+  ///  @since 3.16.0 additional type `InsertReplaceEdit`
   final TextEdit textEdit;
 
   Map<String, dynamic> toJson() {
@@ -7510,7 +7510,7 @@
   }
 
   /// An optional annotation identifer describing the operation.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final String annotationId;
 
   /// A create
@@ -7704,7 +7704,7 @@
 
 /// The parameters sent in notifications/requests for user-initiated creation of
 /// files.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class CreateFilesParams implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(CreateFilesParams.canParse, CreateFilesParams.fromJson);
@@ -8637,7 +8637,7 @@
   }
 
   /// An optional annotation identifer describing the operation.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final String annotationId;
 
   /// A delete
@@ -8832,7 +8832,7 @@
 
 /// The parameters sent in notifications/requests for user-initiated deletes of
 /// files.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class DeleteFilesParams implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(DeleteFilesParams.canParse, DeleteFilesParams.fromJson);
@@ -8966,13 +8966,13 @@
   final String code;
 
   /// An optional property to describe the error code.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final CodeDescription codeDescription;
 
   /// A data entry field that is preserved between a
   /// `textDocument/publishDiagnostics` notification and
   /// `textDocument/codeAction` request.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final dynamic data;
 
   /// The diagnostic's message.
@@ -13537,7 +13537,7 @@
 
   /// A human-readable string that is shown when multiple outlines trees are
   /// shown for the same document.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final String label;
   final bool workDoneProgress;
 
@@ -13766,7 +13766,7 @@
 
   /// A human-readable string that is shown when multiple outlines trees are
   /// shown for the same document.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final String label;
   final bool workDoneProgress;
 
@@ -14358,7 +14358,7 @@
 }
 
 /// Represents information on a file/folder create.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class FileCreate implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(FileCreate.canParse, FileCreate.fromJson);
@@ -14428,7 +14428,7 @@
 }
 
 /// Represents information on a file/folder delete.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class FileDelete implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(FileDelete.canParse, FileDelete.fromJson);
@@ -14686,7 +14686,7 @@
 
 /// A pattern to describe in which file operation requests or notifications the
 /// server is interested in.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class FileOperationPattern implements ToJsonable {
   static const jsonHandler = LspJsonHandler(
       FileOperationPattern.canParse, FileOperationPattern.fromJson);
@@ -14812,7 +14812,7 @@
 }
 
 /// A pattern kind describing if a glob pattern matches a file a folder or both.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class FileOperationPatternKind {
   const FileOperationPatternKind(this._value);
   const FileOperationPatternKind.fromJson(this._value);
@@ -14842,7 +14842,7 @@
 }
 
 /// Matching options for the file operation pattern.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class FileOperationPatternOptions implements ToJsonable {
   static const jsonHandler = LspJsonHandler(
       FileOperationPatternOptions.canParse,
@@ -14904,7 +14904,7 @@
 }
 
 /// The options to register for file operations.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class FileOperationRegistrationOptions implements ToJsonable {
   static const jsonHandler = LspJsonHandler(
       FileOperationRegistrationOptions.canParse,
@@ -14985,7 +14985,7 @@
 }
 
 /// Represents information on a file/folder rename.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class FileRename implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(FileRename.canParse, FileRename.fromJson);
@@ -16950,7 +16950,7 @@
   ///
   /// Uses IETF language tags as the value's syntax (See
   /// https://en.wikipedia.org/wiki/IETF_language_tag)
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final String locale;
 
   /// The process Id of the parent process that started the server. Is null if
@@ -17483,7 +17483,7 @@
 }
 
 /// A special text edit to provide an insert and a replace operation.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class InsertReplaceEdit implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(InsertReplaceEdit.canParse, InsertReplaceEdit.fromJson);
@@ -17654,7 +17654,7 @@
 }
 
 /// How whitespace and indentation is handled during completion item insertion.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class InsertTextMode {
   const InsertTextMode(this._value);
   const InsertTextMode.fromJson(this._value);
@@ -18613,7 +18613,7 @@
 }
 
 /// Client capabilities specific to the used markdown parser.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class MarkdownClientCapabilities implements ToJsonable {
   static const jsonHandler = LspJsonHandler(
       MarkdownClientCapabilities.canParse, MarkdownClientCapabilities.fromJson);
@@ -20689,13 +20689,13 @@
   }
 
   /// Client supports a codeDescription property
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final bool codeDescriptionSupport;
 
   /// Whether code action supports the `data` property which is preserved
   /// between a `textDocument/publishDiagnostics` and `textDocument/codeAction`
   /// request.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final bool dataSupport;
 
   /// Whether the clients accepts diagnostics with related information.
@@ -22013,7 +22013,7 @@
   /// operations returned via the rename request's workspace edit by for example
   /// presenting the workspace edit in the user interface and asking for
   /// confirmation.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final bool honorsChangeAnnotations;
 
   /// Client supports testing for validity of rename operations before
@@ -22161,7 +22161,7 @@
   }
 
   /// An optional annotation identifer describing the operation.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final String annotationId;
 
   /// A rename
@@ -22378,7 +22378,7 @@
 
 /// The parameters sent in notifications/requests for user-initiated renames of
 /// files.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class RenameFilesParams implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(RenameFilesParams.canParse, RenameFilesParams.fromJson);
@@ -24049,7 +24049,14 @@
   /// Whether the client supports tokens that can overlap each other.
   final bool overlappingTokenSupport;
 
-  /// Which requests the client supports and might send to the server.
+  /// Which requests the client supports and might send to the server depending
+  /// on the server's capability. Please note that clients might not show
+  /// semantic tokens or degrade some of the user experience if a range or full
+  /// request is advertised by the client but not provided by the server. If for
+  /// example the client capability `requests.full` and `request.range` are both
+  /// set to true but the server only provides a range provider the client might
+  /// not render a minimap correctly or might even decide to not show any
+  /// semantic tokens at all.
   final SemanticTokensClientCapabilitiesRequests requests;
 
   /// The token modifiers that the client supports.
@@ -26388,12 +26395,12 @@
       implementationProvider;
 
   /// The server provides linked editing range support.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final Either3<bool, LinkedEditingRangeOptions,
       LinkedEditingRangeRegistrationOptions> linkedEditingRangeProvider;
 
   /// Whether server provides moniker support.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final Either3<bool, MonikerOptions, MonikerRegistrationOptions>
       monikerProvider;
 
@@ -27203,7 +27210,7 @@
   }
 
   /// The server is interested in file notifications/requests.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final ServerCapabilitiesFileOperations fileOperations;
 
   /// The server supports workspace folder.
@@ -27350,7 +27357,7 @@
 }
 
 /// Client capabilities for the show document request.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class ShowDocumentClientCapabilities implements ToJsonable {
   static const jsonHandler = LspJsonHandler(
       ShowDocumentClientCapabilities.canParse,
@@ -27423,7 +27430,7 @@
 }
 
 /// Params to show a document.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class ShowDocumentParams implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(ShowDocumentParams.canParse, ShowDocumentParams.fromJson);
@@ -27562,7 +27569,7 @@
 }
 
 /// The result of an show document request.
-///  @since 3.16.0 - proposed state
+///  @since 3.16.0
 class ShowDocumentResult implements ToJsonable {
   static const jsonHandler =
       LspJsonHandler(ShowDocumentResult.canParse, ShowDocumentResult.fromJson);
@@ -28345,7 +28352,7 @@
 
   /// The client supports the `activeParameter` property on
   /// `SignatureInformation` literal.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final bool activeParameterSupport;
 
   /// Client supports the follow content formats for the documentation property.
@@ -29115,7 +29122,7 @@
   /// The index of the active parameter.
   ///
   /// If provided, this is used in place of `SignatureHelp.activeParameter`.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final num activeParameter;
 
   /// The human-readable doc-comment of this signature. Will be shown in the UI
@@ -33611,7 +33618,7 @@
   ///
   /// Whether clients honor this property depends on the client capability
   /// `workspace.changeAnnotationSupport`.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final Map<String, ChangeAnnotation> changeAnnotations;
 
   /// Holds changes to existing resources.
@@ -33770,7 +33777,7 @@
 
   /// Whether the client in general supports change annotations on text edits,
   /// create file, rename file and delete file changes.
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final WorkspaceEditClientCapabilitiesChangeAnnotationSupport
       changeAnnotationSupport;
 
@@ -33785,7 +33792,7 @@
   /// Whether the client normalizes line endings to the client specific setting.
   /// If set to `true` the client will normalize line ending characters in a
   /// workspace edit to the client specific new line character(s).
-  ///  @since 3.16.0 - proposed state
+  ///  @since 3.16.0
   final bool normalizesLineEndings;
 
   /// The resource operations the client supports. Clients should at least
diff --git a/pkg/analysis_server/lib/src/lsp/client_configuration.dart b/pkg/analysis_server/lib/src/lsp/client_configuration.dart
index 8af5a85..26ad2d0 100644
--- a/pkg/analysis_server/lib/src/lsp/client_configuration.dart
+++ b/pkg/analysis_server/lib/src/lsp/client_configuration.dart
@@ -31,6 +31,9 @@
   bool get previewCommitCharacters =>
       _settings['previewCommitCharacters'] ?? false;
 
+  /// Whether diagnostics should be generated for TODO comments.
+  bool get showTodos => _settings['showTodos'] ?? false;
+
   /// Returns whether or not the provided new configuration changes any values
   /// that would require analysis roots to be updated.
   bool affectsAnalysisRoots(Map<String, dynamic> newConfig) {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
index be00dc9..c1e6a39 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
@@ -32,6 +32,7 @@
 import 'package:analysis_server/src/lsp/handlers/handler_shutdown.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_signature_help.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_text_document_changes.dart';
+import 'package:analysis_server/src/lsp/handlers/handler_will_rename_files.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_workspace_configuration.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_workspace_symbols.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -100,6 +101,7 @@
     registerHandler(WorkspaceSymbolHandler(server));
     registerHandler(WorkspaceDidChangeConfigurationMessageHandler(server));
     registerHandler(ReanalyzeHandler(server));
+    registerHandler(WillRenameFilesHandler(server));
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_will_rename_files.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_will_rename_files.dart
new file mode 100644
index 0000000..2beb369
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_will_rename_files.dart
@@ -0,0 +1,60 @@
+// 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 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+import 'package:analysis_server/src/lsp/mapping.dart';
+import 'package:analysis_server/src/services/refactoring/refactoring.dart';
+
+class WillRenameFilesHandler extends MessageHandler<RenameFilesParams, void> {
+  WillRenameFilesHandler(LspAnalysisServer server) : super(server);
+  @override
+  Method get handlesMessage => Method.workspace_willRenameFiles;
+
+  @override
+  LspJsonHandler<RenameFilesParams> get jsonHandler =>
+      RenameFilesParams.jsonHandler;
+
+  @override
+  Future<ErrorOr<WorkspaceEdit>> handle(
+      RenameFilesParams params, CancellationToken token) async {
+    final files = params?.files ?? [];
+    // For performance reasons, only single-file rename/moves are currently supported.
+    if (files.length > 1 || files.any((f) => !f.oldUri.endsWith('.dart'))) {
+      return success(null);
+    }
+
+    final file = files.single;
+    final oldPath = pathOfUri(Uri.tryParse(file.oldUri));
+    final newPath = pathOfUri(Uri.tryParse(file.newUri));
+    return oldPath.mapResult((oldPath) =>
+        newPath.mapResult((newPath) => _renameFile(oldPath, newPath)));
+  }
+
+  Future<ErrorOr<WorkspaceEdit>> _renameFile(
+      String oldPath, String newPath) async {
+    final resolvedUnit = await server.getResolvedUnit(oldPath);
+    if (resolvedUnit == null) {
+      return success(null);
+    }
+
+    final refactoring = MoveFileRefactoring(server.resourceProvider,
+        server.refactoringWorkspace, resolvedUnit, oldPath)
+      ..newFile = newPath;
+
+    // If we're unable to update imports for a rename, we should silently do
+    // nothing rather than interrupt the users file rename with an error.
+    final results = await refactoring.checkAllConditions();
+    if (results.hasFatalError) {
+      return success(null);
+    }
+
+    final change = await refactoring.createChange();
+    final edit = createWorkspaceEdit(server, change.edits);
+
+    return success(edit);
+  }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index bc6f7b7..38ed011 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -773,9 +773,7 @@
       if (analysisServer.shouldSendErrorsNotificationFor(path)) {
         final serverErrors = protocol.mapEngineErrors(
             result,
-            result.errors
-                .where((e) => e.errorCode.type != ErrorType.TODO)
-                .toList(),
+            result.errors.where(_shouldSendDiagnostic).toList(),
             (result, error, [severity]) => toDiagnostic(
                   result,
                   error,
@@ -876,4 +874,8 @@
         ?.forEach((path) => analysisServer.publishDiagnostics(path, const []));
     driver.dispose();
   }
+
+  bool _shouldSendDiagnostic(AnalysisError error) =>
+      error.errorCode.type != ErrorType.TODO ||
+      analysisServer.clientConfiguration.showTodos;
 }
diff --git a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
index 81005d6..182395f 100644
--- a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
+++ b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
@@ -35,6 +35,9 @@
     Method.textDocument_codeAction,
     Method.textDocument_rename,
     Method.textDocument_foldingRange,
+    // workspace.fileOperations covers all file operation methods but we only
+    // support this one.
+    Method.workspace_willRenameFiles,
   ];
   final ClientCapabilities _capabilities;
 
@@ -60,6 +63,9 @@
   bool get documentSymbol =>
       _capabilities.textDocument?.documentSymbol?.dynamicRegistration ?? false;
 
+  bool get fileOperations =>
+      _capabilities.workspace?.fileOperations?.dynamicRegistration ?? false;
+
   bool get folding =>
       _capabilities.textDocument?.foldingRange?.dynamicRegistration ?? false;
 
@@ -93,6 +99,19 @@
 }
 
 class ServerCapabilitiesComputer {
+  static final fileOperationRegistrationOptions =
+      FileOperationRegistrationOptions(
+    filters: [
+      FileOperationFilter(
+        scheme: 'file',
+        pattern: FileOperationPattern(
+          glob: '**/*.dart',
+          matches: FileOperationPatternKind.file,
+        ),
+      )
+    ],
+  );
+
   final LspAnalysisServer _server;
 
   /// Map from method name to current registration data.
@@ -213,10 +232,16 @@
       ),
       workspaceSymbolProvider: Either2<bool, WorkspaceSymbolOptions>.t1(true),
       workspace: ServerCapabilitiesWorkspace(
-          workspaceFolders: WorkspaceFoldersServerCapabilities(
-        supported: true,
-        changeNotifications: Either2<String, bool>.t2(true),
-      )),
+        workspaceFolders: WorkspaceFoldersServerCapabilities(
+          supported: true,
+          changeNotifications: Either2<String, bool>.t2(true),
+        ),
+        fileOperations: dynamicRegistrations.fileOperations
+            ? null
+            : ServerCapabilitiesFileOperations(
+                willRename: fileOperationRegistrationOptions,
+              ),
+      ),
     );
   }
 
@@ -394,6 +419,11 @@
       TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
     );
     register(
+      dynamicRegistrations.fileOperations,
+      Method.workspace_willRenameFiles,
+      fileOperationRegistrationOptions,
+    );
+    register(
       dynamicRegistrations.didChangeConfiguration,
       Method.workspace_didChangeConfiguration,
     );
diff --git a/pkg/analysis_server/lib/src/services/completion/yaml/producer.dart b/pkg/analysis_server/lib/src/services/completion/yaml/producer.dart
index cc96113..f4edf9b 100644
--- a/pkg/analysis_server/lib/src/services/completion/yaml/producer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/yaml/producer.dart
@@ -90,13 +90,8 @@
       try {
         for (var child in dir.getChildren()) {
           var name = child.shortName;
-          if (child is Folder) {
-            if (!name.startsWith('.')) {
-              yield identifier(name);
-            }
-          } else if (child is File) {
-            yield identifier(name);
-          }
+          var relevance = name.startsWith('.') ? 500 : 1000;
+          yield identifier(name, relevance: relevance);
         }
       } on FileSystemException {
         // Guard against I/O exceptions.
@@ -171,14 +166,9 @@
   const Producer();
 
   /// A utility method used to create a suggestion for the [identifier].
-  CompletionSuggestion identifier(String identifier) => CompletionSuggestion(
-      CompletionSuggestionKind.IDENTIFIER,
-      1000,
-      identifier,
-      identifier.length,
-      0,
-      false,
-      false);
+  CompletionSuggestion identifier(String identifier, {int relevance = 1000}) =>
+      CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER, relevance,
+          identifier, identifier.length, 0, false, false);
 
   /// Return the completion suggestions appropriate to this location.
   Iterable<CompletionSuggestion> suggestions(YamlCompletionRequest request);
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index fa74016..66ec3ce 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -34,8 +34,9 @@
   Future<void> test_commitCharacter_completionItem() async {
     await provideConfig(
       () => initialize(
-        textDocumentCapabilities: withAllSupportedDynamicRegistrations(
-            emptyTextDocumentClientCapabilities),
+        textDocumentCapabilities:
+            withAllSupportedTextDocumentDynamicRegistrations(
+                emptyTextDocumentClientCapabilities),
         workspaceCapabilities:
             withConfigurationSupport(emptyWorkspaceClientCapabilities),
       ),
@@ -63,8 +64,9 @@
       () => monitorDynamicRegistrations(
         registrations,
         () => initialize(
-            textDocumentCapabilities: withAllSupportedDynamicRegistrations(
-                emptyTextDocumentClientCapabilities),
+            textDocumentCapabilities:
+                withAllSupportedTextDocumentDynamicRegistrations(
+                    emptyTextDocumentClientCapabilities),
             workspaceCapabilities:
                 withDidChangeConfigurationDynamicRegistration(
                     withConfigurationSupport(
diff --git a/pkg/analysis_server/test/lsp/diagnostic_test.dart b/pkg/analysis_server/test/lsp/diagnostic_test.dart
index d2555e9..5adeef9 100644
--- a/pkg/analysis_server/test/lsp/diagnostic_test.dart
+++ b/pkg/analysis_server/test/lsp/diagnostic_test.dart
@@ -285,16 +285,63 @@
 
   Future<void> test_todos() async {
     // TODOs only show up if there's also some code in the file.
-    const initialContents = '''
+    const contents = '''
     // TODO: This
     String a = "";
     ''';
-    newFile(mainFilePath, content: initialContents);
+    newFile(mainFilePath, content: contents);
 
     final firstDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
+    await provideConfig(
+      () => initialize(
+          workspaceCapabilities:
+              withConfigurationSupport(emptyWorkspaceClientCapabilities)),
+      {'showTodos': true},
+    );
+    final initialDiagnostics = await firstDiagnosticsUpdate;
+    expect(initialDiagnostics, hasLength(1));
+  }
+
+  Future<void> test_todos_disabled() async {
+    const contents = '''
+    // TODO: This
+    String a = "";
+    ''';
+    newFile(mainFilePath, content: contents);
+
+    final firstDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
+    // TODOs are disabled by default so we don't need to send any config.
     await initialize();
     final initialDiagnostics = await firstDiagnosticsUpdate;
-    // TODOs should not be sent by LSP.
     expect(initialDiagnostics, hasLength(0));
   }
+
+  Future<void> test_todos_enabledAfterAnalysis() async {
+    const contents = '''
+    // TODO: This
+    String a = "";
+    ''';
+
+    final initialAnalysis = waitForAnalysisComplete();
+    final firstDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
+    await provideConfig(
+      () => initialize(
+          workspaceCapabilities:
+              withConfigurationSupport(emptyWorkspaceClientCapabilities)),
+      {},
+    );
+    await openFile(mainFileUri, contents);
+    final initialDiagnostics = await firstDiagnosticsUpdate;
+    expect(initialDiagnostics, hasLength(0));
+
+    // Ensure initial analysis completely finished before we continue.
+    await initialAnalysis;
+
+    // Enable showTodos and update the file to ensure TODOs now come through.
+    final secondDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
+    await updateConfig({'showTodos': true});
+    await replaceFile(222, mainFileUri, contents);
+    final updatedDiagnostics = await secondDiagnosticsUpdate;
+    expect(updatedDiagnostics, hasLength(1));
+  }
 }
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index 613ad4a..bff75d6 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -38,10 +38,13 @@
     final initResponse = await monitorDynamicRegistrations(
       registrations,
       () => initialize(
-          // Support dynamic registration for both text sync + hovers.
-          textDocumentCapabilities: withTextSyncDynamicRegistration(
-              withHoverDynamicRegistration(
-                  emptyTextDocumentClientCapabilities))),
+        // Support dynamic registration for both text sync + hovers.
+        textDocumentCapabilities: withTextSyncDynamicRegistration(
+            withHoverDynamicRegistration(emptyTextDocumentClientCapabilities)),
+        // And also file operations.
+        workspaceCapabilities: withFileOperationDynamicRegistration(
+            emptyWorkspaceClientCapabilities),
+      ),
     );
 
     // Because we support dynamic registration for synchronization, we won't send
@@ -53,12 +56,15 @@
     expect(initResult.capabilities, isNotNull);
     expect(initResult.capabilities.textDocumentSync, isNull);
 
-    // Should contain Hover, DidOpen, DidClose, DidChange.
-    expect(registrations, hasLength(4));
+    // Should contain Hover, DidOpen, DidClose, DidChange, WillRenameFiles.
+    expect(registrations, hasLength(5));
     final hover =
         registrationOptionsFor(registrations, Method.textDocument_hover);
     final change =
         registrationOptionsFor(registrations, Method.textDocument_didChange);
+    final rename = FileOperationRegistrationOptions.fromJson(
+        registrationFor(registrations, Method.workspace_willRenameFiles)
+            ?.registerOptions);
     expect(registrationOptionsFor(registrations, Method.textDocument_didOpen),
         isNotNull);
     expect(registrationOptionsFor(registrations, Method.textDocument_didClose),
@@ -79,6 +85,9 @@
         change.documentSelector
             .any((ds) => ds.pattern == '**/analysis_options.yaml'),
         isTrue);
+
+    expect(rename,
+        equals(ServerCapabilitiesComputer.fileOperationRegistrationOptions));
   }
 
   Future<void> test_dynamicRegistration_notSupportedByClient() async {
@@ -120,6 +129,8 @@
     expect(initResult.capabilities.codeActionProvider, isNotNull);
     expect(initResult.capabilities.renameProvider, isNotNull);
     expect(initResult.capabilities.foldingRangeProvider, isNotNull);
+    expect(initResult.capabilities.workspace.fileOperations.willRename,
+        equals(ServerCapabilitiesComputer.fileOperationRegistrationOptions));
 
     expect(didGetRegisterCapabilityRequest, isFalse);
   }
@@ -147,9 +158,13 @@
     final initResponse = await monitorDynamicRegistrations(
       registrations,
       () => initialize(
-          // Support dynamic registration for everything we support.
-          textDocumentCapabilities: withAllSupportedDynamicRegistrations(
-              emptyTextDocumentClientCapabilities)),
+        // Support dynamic registration for everything we support.
+        textDocumentCapabilities:
+            withAllSupportedTextDocumentDynamicRegistrations(
+                emptyTextDocumentClientCapabilities),
+        workspaceCapabilities: withAllSupportedWorkspaceDynamicRegistrations(
+            emptyWorkspaceClientCapabilities),
+      ),
     );
 
     final initResult = InitializeResult.fromJson(initResponse.result);
@@ -170,6 +185,7 @@
     expect(initResult.capabilities.codeActionProvider, isNull);
     expect(initResult.capabilities.renameProvider, isNull);
     expect(initResult.capabilities.foldingRangeProvider, isNull);
+    expect(initResult.capabilities.workspace.fileOperations, isNull);
 
     // Ensure all expected dynamic registrations.
     for (final expectedRegistration in ClientDynamicRegistrations.supported) {
@@ -186,8 +202,9 @@
     await monitorDynamicRegistrations(
       registrations,
       () => initialize(
-          textDocumentCapabilities: withAllSupportedDynamicRegistrations(
-              emptyTextDocumentClientCapabilities)),
+          textDocumentCapabilities:
+              withAllSupportedTextDocumentDynamicRegistrations(
+                  emptyTextDocumentClientCapabilities)),
     );
 
     final unregisterRequest =
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 2c4f8ab..a832811 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -199,11 +199,12 @@
     return ClientCapabilitiesWorkspace.fromJson(json);
   }
 
-  TextDocumentClientCapabilities withAllSupportedDynamicRegistrations(
+  TextDocumentClientCapabilities
+      withAllSupportedTextDocumentDynamicRegistrations(
     TextDocumentClientCapabilities source,
   ) {
-    // This list should match all of the fields listed in
-    // `ClientDynamicRegistrations.supported`.
+    // This list (when combined with the workspace list) should match all of
+    // the fields listed in `ClientDynamicRegistrations.supported`.
     return extendTextDocumentCapabilities(source, {
       'synchronization': {'dynamicRegistration': true},
       'completion': {'dynamicRegistration': true},
@@ -224,6 +225,16 @@
     });
   }
 
+  ClientCapabilitiesWorkspace withAllSupportedWorkspaceDynamicRegistrations(
+    ClientCapabilitiesWorkspace source,
+  ) {
+    // This list (when combined with the textDocument list) should match all of
+    // the fields listed in `ClientDynamicRegistrations.supported`.
+    return extendWorkspaceCapabilities(source, {
+      'fileOperations': {'dynamicRegistration': true},
+    });
+  }
+
   ClientCapabilitiesWorkspace withApplyEditSupport(
     ClientCapabilitiesWorkspace source,
   ) {
@@ -343,6 +354,14 @@
     });
   }
 
+  ClientCapabilitiesWorkspace withFileOperationDynamicRegistration(
+    ClientCapabilitiesWorkspace source,
+  ) {
+    return extendWorkspaceCapabilities(source, {
+      'fileOperations': {'dynamicRegistration': true}
+    });
+  }
+
   TextDocumentClientCapabilities withHierarchicalDocumentSymbolSupport(
     TextDocumentClientCapabilities source,
   ) {
@@ -1219,6 +1238,14 @@
     );
   }
 
+  Future<WorkspaceEdit> onWillRename(List<FileRename> renames) {
+    final request = makeRequest(
+      Method.workspace_willRenameFiles,
+      RenameFilesParams(files: renames),
+    );
+    return expectSuccessfulResponseTo(request, WorkspaceEdit.fromJson);
+  }
+
   Future openFile(Uri uri, String content, {num version = 1}) async {
     var notification = makeNotification(
       Method.textDocument_didOpen,
diff --git a/pkg/analysis_server/test/lsp/test_all.dart b/pkg/analysis_server/test/lsp/test_all.dart
index ea56793..0756d4e 100644
--- a/pkg/analysis_server/test/lsp/test_all.dart
+++ b/pkg/analysis_server/test/lsp/test_all.dart
@@ -37,6 +37,7 @@
 import 'server_test.dart' as server;
 import 'signature_help_test.dart' as signature_help;
 import 'super_test.dart' as get_super;
+import 'will_rename_files_test.dart' as will_rename_files;
 import 'workspace_symbols_test.dart' as workspace_symbols;
 
 void main() {
@@ -74,6 +75,7 @@
     rename.main();
     server.main();
     signature_help.main();
+    will_rename_files.main();
     workspace_symbols.main();
   }, name: 'lsp');
 }
diff --git a/pkg/analysis_server/test/lsp/will_rename_files_test.dart b/pkg/analysis_server/test/lsp/will_rename_files_test.dart
new file mode 100644
index 0000000..e9b6fee
--- /dev/null
+++ b/pkg/analysis_server/test/lsp/will_rename_files_test.dart
@@ -0,0 +1,60 @@
+// 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:async';
+
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'server_abstract.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(WillRenameFilesTest);
+  });
+}
+
+@reflectiveTest
+class WillRenameFilesTest extends AbstractLspAnalysisServerTest {
+  Future<void> test_rename_updatesImports() async {
+    final otherFilePath = join(projectFolderPath, 'lib', 'other.dart');
+    final otherFileUri = Uri.file(otherFilePath);
+    final otherFileNewPath = join(projectFolderPath, 'lib', 'other_new.dart');
+    final otherFileNewUri = Uri.file(otherFileNewPath);
+
+    final mainContent = '''
+import 'other.dart';
+
+final a = A();
+''';
+
+    final otherContent = '''
+class A {}
+''';
+
+    final expectedMainContent = '''
+import 'other_new.dart';
+
+final a = A();
+''';
+
+    await initialize();
+    await openFile(mainFileUri, mainContent);
+    await openFile(otherFileUri, otherContent);
+    final edit = await onWillRename([
+      FileRename(
+        oldUri: otherFileUri.toString(),
+        newUri: otherFileNewUri.toString(),
+      ),
+    ]);
+
+    // Ensure applying the edit will give us the expected content.
+    final contents = {
+      mainFilePath: withoutMarkers(mainContent),
+    };
+    applyChanges(contents, edit.changes);
+    expect(contents[mainFilePath], equals(expectedMainContent));
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart b/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
index 510843f..1435f6c 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
@@ -6,8 +6,6 @@
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/assist_internal.dart';
 import 'package:analysis_server/src/services/correction/change_workspace.dart';
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/instrumentation/service.dart';
 import 'package:analyzer/src/test_utilities/platform.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart'
     hide AnalysisError;
@@ -17,6 +15,7 @@
 import 'package:test/test.dart';
 
 import '../../../../abstract_single_unit.dart';
+import '../../../../utils/test_instrumentation_service.dart';
 
 export 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
 
@@ -194,7 +193,7 @@
 
   Future<List<Assist>> _computeAssists() async {
     var context = DartAssistContextImpl(
-      _TestInstrumentationService(),
+      TestInstrumentationService(),
       workspace,
       testAnalysisResult,
       _offset,
@@ -213,19 +212,3 @@
     return positions;
   }
 }
-
-class _TestInstrumentationService implements InstrumentationService {
-  @override
-  void logException(
-    exception, [
-    StackTrace stackTrace,
-    List<InstrumentationServiceAttachment> attachments,
-  ]) {
-    throw CaughtException(exception, stackTrace);
-  }
-
-  @override
-  dynamic noSuchMethod(Invocation invocation) {
-    return super.noSuchMethod(invocation);
-  }
-}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart
index c7f2b1e..1e52915 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart
@@ -107,6 +107,16 @@
     verifyNoTestUnitErrors = false;
     await resolveTestCode('''
 void f() {
+  "abc
+}
+''');
+    await assertNoAssistAt('"');
+  }
+
+  Future<void> test_doubleQuoted_unterminated_empty() async {
+    verifyNoTestUnitErrors = false;
+    await resolveTestCode('''
+void f() {
   "
 }
 ''');
@@ -192,6 +202,16 @@
     verifyNoTestUnitErrors = false;
     await resolveTestCode('''
 void f() {
+  'abc
+}
+''');
+    await assertNoAssistAt("'");
+  }
+
+  Future<void> test_singleQuoted_unterminated_empty() async {
+    verifyNoTestUnitErrors = false;
+    await resolveTestCode('''
+void f() {
   '
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
index 1f45cc4..a239042 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
@@ -4,7 +4,6 @@
 
 import 'package:analysis_server/src/services/correction/bulk_fix_processor.dart';
 import 'package:analysis_server/src/services/correction/change_workspace.dart';
-import 'package:analyzer/instrumentation/service.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/services/available_declarations.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -12,6 +11,7 @@
 import 'package:test/test.dart';
 
 import '../../../../../abstract_single_unit.dart';
+import '../../../../../utils/test_instrumentation_service.dart';
 
 /// A base class defining support for writing bulk fix processor tests.
 abstract class BulkFixProcessorTest extends AbstractSingleUnitTest {
@@ -58,8 +58,7 @@
     var tracker = DeclarationsTracker(MemoryByteStore(), resourceProvider);
     var analysisContext = contextFor(testFile);
     tracker.addContext(analysisContext);
-    var processor =
-        BulkFixProcessor(InstrumentationService.NULL_SERVICE, workspace);
+    var processor = BulkFixProcessor(TestInstrumentationService(), workspace);
     await processor.fixErrors([analysisContext]);
     return processor;
   }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
index 0900c1b..46ff4d4 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
@@ -8,7 +8,6 @@
 import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
 import 'package:analysis_server/src/services/correction/fix_internal.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/instrumentation/service.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/error/lint_codes.dart';
 import 'package:analyzer/src/services/available_declarations.dart';
@@ -22,6 +21,7 @@
 
 import '../../../../abstract_context.dart';
 import '../../../../abstract_single_unit.dart';
+import '../../../../utils/test_instrumentation_service.dart';
 
 export 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
 
@@ -274,7 +274,7 @@
     tracker.addContext(analysisContext);
 
     var context = DartFixContextImpl(
-      InstrumentationService.NULL_SERVICE,
+      TestInstrumentationService(),
       workspace,
       testAnalysisResult,
       error,
diff --git a/pkg/analysis_server/test/utils/test_instrumentation_service.dart b/pkg/analysis_server/test/utils/test_instrumentation_service.dart
new file mode 100644
index 0000000..4fd7157
--- /dev/null
+++ b/pkg/analysis_server/test/utils/test_instrumentation_service.dart
@@ -0,0 +1,23 @@
+// 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 'package:analyzer/exception/exception.dart';
+import 'package:analyzer/instrumentation/service.dart';
+
+/// Implementation of [InstrumentationService] that throws on [logException].
+class TestInstrumentationService implements InstrumentationService {
+  @override
+  void logException(
+    exception, [
+    StackTrace stackTrace,
+    List<InstrumentationServiceAttachment> attachments,
+  ]) {
+    throw CaughtException(exception, stackTrace);
+  }
+
+  @override
+  dynamic noSuchMethod(Invocation invocation) {
+    return super.noSuchMethod(invocation);
+  }
+}
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index 961b2c5..27649ab 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -33,6 +33,7 @@
 - `dart.enableSdkFormatter`: When set to `false`, prevents registration (or unregisters) the SDK formatter. When set to `true` or not supplied, will register/reregister the SDK formatter.
 - `dart.lineLength`: The number of characters the formatter should wrap code at. If unspecified, code will be wrapped at `80` characters.
 - `dart.completeFunctionCalls`: Completes functions/methods with their required parameters.
+- `dart.showTodos`: Whether to generate diagnostics for TODO comments. If unspecified, diagnostics will not be generated.
 
 ## Method Status
 
@@ -66,6 +67,7 @@
 | workspace/symbol | ✅ | ✅ | | ✅ | ✅ |
 | workspace/executeCommand | ✅ | ✅ | | ✅ | ✅ |
 | workspace/applyEdit | ✅ | ✅ | | ✅ | ✅ |
+| workspace/onWillRenameFiles | ✅ | ✅ | | ✅ | ✅ |
 | textDocument/didOpen | ✅ | ✅ | ✅ | ✅ | ✅ |
 | textDocument/didChange | ✅ | ✅ | ✅ | ✅ | ✅ |
 | textDocument/willSave | | | | | |
diff --git a/pkg/analysis_server/tool/lsp_spec/lsp_specification.md b/pkg/analysis_server/tool/lsp_spec/lsp_specification.md
index 8bd0c6b..d7c94f3 100644
--- a/pkg/analysis_server/tool/lsp_spec/lsp_specification.md
+++ b/pkg/analysis_server/tool/lsp_spec/lsp_specification.md
@@ -30,7 +30,7 @@
 ---
 # Language Server Protocol Specification - 3.16
 
-This document describes the upcoming 3.16.x version of the language server protocol. An implementation for node of the 3.16.x version of the protocol can be found [here](https://github.com/Microsoft/vscode-languageserver-node).
+This document describes the 3.16.x version of the language server protocol. An implementation for node of the 3.16.x version of the protocol can be found [here](https://github.com/Microsoft/vscode-languageserver-node).
 
 **Note:** edits to this specification can be made via a pull request against this markdown [document](https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-16.md).
 
@@ -38,12 +38,14 @@
 
 All new 3.16 features are tagged with a corresponding since version 3.16 text or in JSDoc using `@since 3.16.0` annotation. Major new feature are:
 
-- Call Hierarchy support
 - Semantic Token support
-- Better trace logging support
+- Call Hierarchy support
+- Linked Editing support
 - Moniker support
-- Code Action disabled support
-- Code Action resolve support
+- Events for file operations (create, rename, delete)
+- Change annotation support for text edits and file operations (create, rename, delete)
+
+A detailed list of the changes can be found in the [change log](#version_3_16_0)
 
 The version of the specification is used to group features into a new specification release and to refer to their first appearance. Features in the spec are kept compatible using so called capability flags which are exchanged between the client and the server during initialization.
 
@@ -330,10 +332,6 @@
 
 URI's are transferred as strings. The URI's format is defined in [http://tools.ietf.org/html/rfc3986](http://tools.ietf.org/html/rfc3986)
 
-```typescript
-type URI = string;
-```
-
 ```
   foo://example.com:8042/over/there?name=ferret#nose
   \_/   \______________/\_________/ \_________/ \__/
@@ -534,7 +532,7 @@
 	/**
 	 * An optional property to describe the error code.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	codeDescription?: CodeDescription;
 
@@ -567,7 +565,7 @@
 	 * `textDocument/publishDiagnostics` notification and
 	 * `textDocument/codeAction` request.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	data?: unknown;
 }
@@ -648,7 +646,7 @@
 /**
  * Structure to capture a description for an error code.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface CodeDescription {
 	/**
@@ -708,7 +706,7 @@
 /**
  * Additional information that describes document changes.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface ChangeAnnotation {
 	/**
@@ -739,7 +737,7 @@
  * An identifier referring to a change annotation managed by a workspace
  * edit.
  *
- * @since 3.16.0 - proposed state.
+ * @since 3.16.0.
  */
 export type ChangeAnnotationIdentifier = string;
 
@@ -747,7 +745,7 @@
 /**
  * A special text edit with an additional change annotation.
  *
- * @since 3.16.0 - proposed state.
+ * @since 3.16.0.
  */
 export interface AnnotatedTextEdit extends TextEdit {
 	/**
@@ -830,7 +828,7 @@
 	/**
 	 * An optional annotation identifer describing the operation.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	annotationId?: ChangeAnnotationIdentifier;
 }
@@ -877,7 +875,7 @@
 	/**
 	 * An optional annotation identifer describing the operation.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	annotationId?: ChangeAnnotationIdentifier;
 }
@@ -919,7 +917,7 @@
 	/**
 	 * An optional annotation identifer describing the operation.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	annotationId?: ChangeAnnotationIdentifier;
 }
@@ -964,7 +962,7 @@
 	 * Whether clients honor this property depends on the client capability
 	 * `workspace.changeAnnotationSupport`.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	changeAnnotations?: {
 		[id: string /* ChangeAnnotationIdentifier */]: ChangeAnnotation;
@@ -1011,7 +1009,7 @@
 	 * If set to `true` the client will normalize line ending characters
 	 * in a workspace edit to the client specific new line character(s).
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	normalizesLineEndings?: boolean;
 
@@ -1019,7 +1017,7 @@
 	 * Whether the client in general supports change annotations on text edits,
 	 * create file, rename file and delete file changes.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	changeAnnotationSupport?: {
         /**
@@ -1395,7 +1393,7 @@
 /**
  * Client capabilities specific to the used markdown parser.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface MarkdownClientCapabilities {
 	/**
@@ -1746,7 +1744,7 @@
 	 * Uses IETF language tags as the value's syntax
 	 * (See https://en.wikipedia.org/wiki/IETF_language_tag)
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	locale?: string;
 
@@ -2019,7 +2017,7 @@
 		 * Capabilities specific to the semantic token requests scoped to the
 		 * workspace.
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		 semanticTokens?: SemanticTokensWorkspaceClientCapabilities;
 
@@ -2027,14 +2025,14 @@
 		 * Capabilities specific to the code lens requests scoped to the
 		 * workspace.
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		codeLens?: CodeLensWorkspaceClientCapabilities;
 
 		/**
 		 * The client has support for file requests/notifications.
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		fileOperations?: {
 			/**
@@ -2096,14 +2094,14 @@
 		/**
 		 * Capabilities specific to the showMessage request
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		showMessage?: ShowMessageRequestClientCapabilities;
 
 		/**
 		 * Client capabilities for the show document request.
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		showDocument?: ShowDocumentClientCapabilities;
 	}
@@ -2111,20 +2109,20 @@
 	/**
 	 * General client capabilities.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	general?: {
 		/**
 		 * Client capabilities specific to regular expressions.
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		regularExpressions?: RegularExpressionsClientCapabilities;
 
 		/**
 		 * Client capabilities specific to the client's markdown parser.
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		markdown?: MarkdownClientCapabilities;
 	}
@@ -2338,7 +2336,7 @@
 	/**
 	 * The server provides linked editing range support.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	linkedEditingRangeProvider?: boolean | LinkedEditingRangeOptions
 		| LinkedEditingRangeRegistrationOptions;
@@ -2362,7 +2360,7 @@
 	/**
 	 * Whether server provides moniker support.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
     monikerProvider?: boolean | MonikerOptions | MonikerRegistrationOptions;
 
@@ -2385,7 +2383,7 @@
 		/**
 		 * The server is interested in file notifications/requests.
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		fileOperations?: {
 			/**
@@ -2636,7 +2634,7 @@
 /**
  * Client capabilities for the show document request.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface ShowDocumentClientCapabilities {
 	/**
@@ -2655,7 +2653,7 @@
 /**
  * Params to show a document.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface ShowDocumentParams {
 	/**
@@ -2696,7 +2694,7 @@
 /**
  * The result of an show document request.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface ShowDocumentResult {
 	/**
@@ -3425,7 +3423,7 @@
 /**
  * The options to register for file operations.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 interface FileOperationRegistrationOptions {
 	/**
@@ -3438,7 +3436,7 @@
  * A pattern kind describing if a glob pattern matches a file a folder or
  * both.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export namespace FileOperationPatternKind {
 	/**
@@ -3457,7 +3455,7 @@
 /**
  * Matching options for the file operation pattern.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface FileOperationPatternOptions {
 
@@ -3471,7 +3469,7 @@
  * A pattern to describe in which file operation requests or notifications
  * the server is interested in.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 interface FileOperationPattern {
 	/**
@@ -3535,7 +3533,7 @@
  * The parameters sent in notifications/requests for user-initiated creation
  * of files.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface CreateFilesParams {
 
@@ -3547,7 +3545,7 @@
 /**
  * Represents information on a file/folder create.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface FileCreate {
 
@@ -3609,7 +3607,7 @@
  * The parameters sent in notifications/requests for user-initiated renames
  * of files.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface RenameFilesParams {
 
@@ -3622,7 +3620,7 @@
 /**
  * Represents information on a file/folder rename.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface FileRename {
 
@@ -3689,7 +3687,7 @@
  * The parameters sent in notifications/requests for user-initiated deletes
  * of files.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface DeleteFilesParams {
 
@@ -3701,7 +3699,7 @@
 /**
  * Represents information on a file/folder delete.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface FileDelete {
 
@@ -4205,7 +4203,7 @@
 	/**
 	 * Client supports a codeDescription property
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	codeDescriptionSupport?: boolean;
 
@@ -4214,7 +4212,7 @@
 	 * preserved between a `textDocument/publishDiagnostics` and
 	 * `textDocument/codeAction` request.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	dataSupport?: boolean;
 }
@@ -4317,7 +4315,7 @@
 		 * Client supports insert replace edit to control different behavior if
 		 * a completion item is inserted in the text or should replace text.
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		insertReplaceSupport?: boolean;
 
@@ -4326,7 +4324,7 @@
 		 * completion item. Before version 3.16.0 only the predefined properties
 		 * `documentation` and `details` could be resolved lazily.
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		resolveSupport?: {
 			/**
@@ -4340,7 +4338,7 @@
 		 * a completion item to override the whitespace handling mode
 		 * as defined by the client (see `insertTextMode`).
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		insertTextModeSupport?: {
 			valueSet: InsertTextMode[];
@@ -4541,7 +4539,7 @@
 /**
  * A special text edit to provide an insert and a replace operation.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export interface InsertReplaceEdit {
 	/**
@@ -4564,7 +4562,7 @@
  * How whitespace and indentation is handled during completion
  * item insertion.
  *
- * @since 3.16.0 - proposed state
+ * @since 3.16.0
  */
 export namespace InsertTextMode {
 	/**
@@ -4677,7 +4675,7 @@
 	 * item insertion. If not provided the client's default value depends on
 	 * the `textDocument.completion.insertTextMode` client capability.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	insertTextMode?: InsertTextMode;
 
@@ -4703,7 +4701,7 @@
 	 * must be a prefix of the edit's replace range, that means it must be
 	 * contained and starting at the same position.
 	 *
-	 * @since 3.16.0 additional type `InsertReplaceEdit` - proposed state
+	 * @since 3.16.0 additional type `InsertReplaceEdit`
 	 */
 	textEdit?: TextEdit | InsertReplaceEdit;
 
@@ -5006,7 +5004,7 @@
 		 * The client supports the `activeParameter` property on
 		 * `SignatureInformation` literal.
 		 *
-		 * @since 3.16.0 - proposed state
+		 * @since 3.16.0
 		 */
 		activeParameterSupport?: boolean;
 	};
@@ -5202,7 +5200,7 @@
 	 *
 	 * If provided, this is used in place of `SignatureHelp.activeParameter`.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	activeParameter?: uinteger;
 }
@@ -5703,7 +5701,7 @@
 	 * A human-readable string that is shown when multiple outlines trees
 	 * are shown for the same document.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	label?: string;
 }
@@ -5955,7 +5953,7 @@
 	/**
 	 * Whether code action supports the `disabled` property.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	disabledSupport?: boolean;
 
@@ -5964,7 +5962,7 @@
 	 * preserved between a `textDocument/codeAction` and a
 	 * `codeAction/resolve` request.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	dataSupport?: boolean;
 
@@ -5973,7 +5971,7 @@
 	 * Whether the client supports resolving additional code action
 	 * properties via a separate `codeAction/resolve` request.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	resolveSupport?: {
 		/**
@@ -5989,7 +5987,7 @@
 	 * the workspace edit in the user interface and asking
 	 * for confirmation.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	honorsChangeAnnotations?: boolean;
 }
@@ -6250,7 +6248,7 @@
 	 * A data entry field that is preserved on a code action between
 	 * a `textDocument/codeAction` and a `codeAction/resolve` request.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	data?: any
 }
@@ -6969,7 +6967,7 @@
 	 * the workspace edit in the user interface and asking
 	 * for confirmation.
 	 *
-	 * @since 3.16.0 - proposed state
+	 * @since 3.16.0
 	 */
 	honorsChangeAnnotations?: boolean;
 }
@@ -7620,7 +7618,14 @@
 	dynamicRegistration?: boolean;
 
 	/**
-	 * Which requests the client supports and might send to the server.
+	 * Which requests the client supports and might send to the server
+	 * depending on the server's capability. Please note that clients might not
+	 * show semantic tokens or degrade some of the user experience if a range
+	 * or full request is advertised by the client but not provided by the
+	 * server. If for example the client capability `requests.full` and
+	 * `request.range` are both set to true but the server only provides a
+	 * range provider the client might not render a minimap correctly or might
+	 * even decide to not show any semantic tokens at all.
 	 */
 	requests: {
 		/**
@@ -8129,7 +8134,7 @@
 
 ### <a href="#changeLog" name="changeLog" class="anchor">Change Log</a>
 
-#### <a href="#version_3_16_0" name="version_3_16_0" class="anchor">3.16.0 (xx/xx/xxxx)</a>
+#### <a href="#version_3_16_0" name="version_3_16_0" class="anchor">3.16.0 (12/14/2020)</a>
 
 * Add support for tracing.
 * Add semantic token support.
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 995281e..2f7c026 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -41,6 +41,7 @@
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
+import 'package:analyzer/src/summary2/ast_binary_flags.dart';
 import 'package:meta/meta.dart';
 
 /// TODO(scheglov) We could use generalized Function in
@@ -85,7 +86,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 116;
+  static const int DATA_VERSION = 118;
 
   /// The length of the list returned by [_computeDeclaredVariablesSignature].
   static const int _declaredVariablesSignatureLength = 4;
@@ -147,7 +148,7 @@
       _declaredVariablesSignatureLength);
 
   /// The salt to mix into all hashes used as keys for linked data.
-  final Uint32List _saltForResolution = Uint32List(2 +
+  final Uint32List _saltForResolution = Uint32List(3 +
       AnalysisOptionsImpl.signatureLength +
       _declaredVariablesSignatureLength);
 
@@ -1596,6 +1597,9 @@
     _saltForResolution[index] = enableIndex ? 1 : 0;
     index++;
 
+    _saltForResolution[index] = enableDebugResolutionMarkers ? 1 : 0;
+    index++;
+
     _saltForResolution.setAll(index, _analysisOptions.signature);
     index += AnalysisOptionsImpl.signatureLength;
 
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 1936e65..8ca926c 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -81,7 +81,7 @@
   /// arguments are correct, `false` if there is an error.
   bool checkFromEnvironmentArguments(
       LibraryElementImpl library,
-      NodeList<Expression> arguments,
+      List<Expression> arguments,
       List<DartObjectImpl> argumentValues,
       Map<String, DartObjectImpl> namedArgumentValues,
       InterfaceType expectedDefaultValueType) {
@@ -271,7 +271,7 @@
       constant = (constant as ConstructorElement).declaration;
     }
     if (constant is VariableElement) {
-      VariableElementImpl declaration = constant.declaration;
+      var declaration = constant.declaration as VariableElementImpl;
       Expression initializer = declaration.constantInitializer;
       if (initializer != null) {
         initializer.accept(referenceFinder);
@@ -497,7 +497,7 @@
         definingType,
       );
     }
-    ConstructorElementImpl constructorBase = constructor.declaration;
+    var constructorBase = constructor.declaration as ConstructorElementImpl;
     List<ConstructorInitializer> initializers =
         constructorBase.constantInitializers;
     if (initializers == null) {
@@ -1550,7 +1550,7 @@
       return false;
     } else if (element is SpreadElement) {
       DartObjectImpl elementResult = element.expression.accept(this);
-      Map<DartObject, DartObject> value = elementResult?.toMapValue();
+      Map<DartObjectImpl, DartObjectImpl> value = elementResult?.toMapValue();
       if (value == null) {
         return true;
       }
@@ -1662,9 +1662,9 @@
         return value.value;
       }
     } else if (variableElement is ExecutableElement) {
-      ExecutableElement function = element;
+      var function = element as ExecutableElement;
       if (function.isStatic) {
-        var functionType = node.staticType;
+        var functionType = node.staticType as ParameterizedType;
         return DartObjectImpl(
           typeSystem,
           functionType,
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 5a9f210..d23a5ab 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -267,7 +267,8 @@
   /// This method should be used only for error recovery during analysis,
   /// when instance access to a static class member, defined in this class,
   /// or a superclass.
-  ExecutableElement lookupStaticGetter(String name, LibraryElement library) {
+  PropertyAccessorElement lookupStaticGetter(
+      String name, LibraryElement library) {
     return _first(_implementationsOfGetter(name).where((element) {
       return element.isStatic && element.isAccessibleIn(library);
     }));
@@ -278,7 +279,7 @@
   /// This method should be used only for error recovery during analysis,
   /// when instance access to a static class member, defined in this class,
   /// or a superclass.
-  ExecutableElement lookupStaticMethod(String name, LibraryElement library) {
+  MethodElement lookupStaticMethod(String name, LibraryElement library) {
     return _first(_implementationsOfMethod(name).where((element) {
       return element.isStatic && element.isAccessibleIn(library);
     }));
@@ -289,7 +290,8 @@
   /// This method should be used only for error recovery during analysis,
   /// when instance access to a static class member, defined in this class,
   /// or a superclass.
-  ExecutableElement lookupStaticSetter(String name, LibraryElement library) {
+  PropertyAccessorElement lookupStaticSetter(
+      String name, LibraryElement library) {
     return _first(_implementationsOfSetter(name).where((element) {
       return element.isStatic && element.isAccessibleIn(library);
     }));
@@ -631,7 +633,7 @@
   bool get hasNoSuchMethod {
     MethodElement method = lookUpConcreteMethod(
         FunctionElement.NO_SUCH_METHOD_METHOD_NAME, library);
-    ClassElement definingClass = method?.enclosingElement;
+    var definingClass = method?.enclosingElement as ClassElement;
     return definingClass != null && !definingClass.isDartCoreObject;
   }
 
@@ -902,7 +904,7 @@
       return <ConstructorElement>[];
     }
 
-    ClassElementImpl superElement = supertype.element;
+    var superElement = supertype.element as ClassElementImpl;
 
     // First get the list of constructors of the superclass which need to be
     // forwarded to this class.
@@ -954,9 +956,13 @@
     // substituting type parameters as appropriate.
     return constructorsToForward
         .map((ConstructorElement superclassConstructor) {
-      ConstructorElementImpl implicitConstructor =
-          ConstructorElementImpl(superclassConstructor.name, -1);
+      var containerRef = reference.getChild('@constructor');
+      var name = superclassConstructor.name;
+      var implicitConstructor = ConstructorElementImpl.forLinkedNode(
+          this, containerRef.getChild(name), null);
       implicitConstructor.isSynthetic = true;
+      implicitConstructor.name = name;
+      implicitConstructor.nameOffset = -1;
       implicitConstructor.redirectedConstructor = superclassConstructor;
       var hasMixinWithInstanceVariables = mixins.any(typeHasInstanceVariables);
       implicitConstructor.isConst =
@@ -1065,7 +1071,10 @@
       if (element.isEnum || element.isMixin) {
         return false;
       }
-      if (type.isDartCoreFunction) {
+      if (type.isDartCoreFunction || type.isDartCoreNull) {
+        return false;
+      }
+      if (type.nullabilitySuffix == NullabilitySuffix.question) {
         return false;
       }
       return true;
@@ -1076,9 +1085,19 @@
   /// Return `true` if the given [type] is an [InterfaceType] that can be used
   /// as an interface or a mixin.
   bool _isInterfaceTypeInterface(DartType type) {
-    return type is InterfaceType &&
-        !type.element.isEnum &&
-        !type.isDartCoreFunction;
+    if (type is InterfaceType) {
+      if (type.element.isEnum) {
+        return false;
+      }
+      if (type.isDartCoreFunction || type.isDartCoreNull) {
+        return false;
+      }
+      if (type.nullabilitySuffix == NullabilitySuffix.question) {
+        return false;
+      }
+      return true;
+    }
+    return false;
   }
 
   static void collectAllSupertypes(List<InterfaceType> supertypes,
@@ -7262,7 +7281,7 @@
   @override
   String get name {
     if (linkedNode != null) {
-      TypeParameter node = linkedNode;
+      var node = linkedNode as TypeParameter;
       return node.name.name;
     }
     return super.name;
diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
index 9189fad..a2b00e9 100644
--- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -743,7 +743,7 @@
     FunctionType resultType;
     for (var executable in validOverrides) {
       var type = executable.type;
-      var normalizedType = typeSystem.normalize(type);
+      var normalizedType = typeSystem.normalize(type) as FunctionType;
       if (resultType == null) {
         resultType = normalizedType;
       } else {
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index f343aa1..20ebc91 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -7,7 +7,6 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/display_string_builder.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
@@ -220,7 +219,7 @@
       return null;
     }
 
-    TypeProvider typeProvider;
+    TypeProviderImpl typeProvider;
     var isLegacy = false;
     var combined = substitution;
     if (element is ExecutableMember) {
@@ -237,7 +236,7 @@
       map.addAll(substitution.map);
       combined = Substitution.fromMap(map);
     } else {
-      typeProvider = element.library.typeProvider;
+      typeProvider = element.library.typeProvider as TypeProviderImpl;
     }
 
     if (!isLegacy && combined.map.isEmpty) {
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 50953f8..2b9613f 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -1468,12 +1468,12 @@
   /// search should include the target type. The [visitedInterfaces] is a set
   /// containing all of the interfaces that have been examined, used to prevent
   /// infinite recursion and to optimize the search.
-  static ExecutableElement _lookUpMemberInInterfaces(
+  static T _lookUpMemberInInterfaces<T extends ExecutableElement>(
       InterfaceType targetType,
       bool includeTargetType,
       LibraryElement library,
       HashSet<ClassElement> visitedInterfaces,
-      ExecutableElement Function(InterfaceType type) getMember) {
+      T Function(InterfaceType type) getMember) {
     // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the
     // specification (titled "Inheritance and Overriding" under "Interfaces")
     // describes a much more complex scheme for finding the inherited member.
diff --git a/pkg/analyzer/lib/src/dart/element/type_algebra.dart b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
index a6ca14b..79ee7f7 100644
--- a/pkg/analyzer/lib/src/dart/element/type_algebra.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
@@ -160,7 +160,7 @@
 
   /// Substitutes the type parameters on the class of [type] with the
   /// type arguments provided in [type].
-  static Substitution fromInterfaceType(InterfaceType type) {
+  static MapSubstitution fromInterfaceType(InterfaceType type) {
     if (type.typeArguments.isEmpty) {
       return _NullSubstitution.instance;
     }
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 0fab9d3..6f59ded 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -193,10 +193,14 @@
   }
 
   void labeledStatement_enter(LabeledStatement node) {
+    if (flow == null) return;
+
     flow.labeledStatement_begin(node);
   }
 
   void labeledStatement_exit(LabeledStatement node) {
+    if (flow == null) return;
+
     flow.labeledStatement_end();
   }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
index 0f3a2b1..aec4def 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
@@ -69,7 +69,7 @@
       if (_flowAnalysis.flow != null && !isFunctionDeclaration) {
         var bodyContext = BodyInferenceContext.of(node.body);
         _resolver.checkForBodyMayCompleteNormally(
-          returnType: bodyContext.contextType,
+          returnType: bodyContext?.contextType,
           body: body,
           errorNode: body,
         );
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 99ead99..95472fb 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -49,7 +49,7 @@
 
   /// A flag indicating whether a surrounding member is annotated as
   /// `@doNotStore`.
-  bool _inDoNotStoreMember;
+  bool _inDoNotStoreMember = false;
 
   /// The error reporter by which errors will be reported.
   final ErrorReporter _errorReporter;
@@ -297,7 +297,7 @@
 
   @override
   void visitClassDeclaration(ClassDeclaration node) {
-    ClassElementImpl element = node.declaredElement;
+    var element = node.declaredElement as ClassElementImpl;
     _enclosingClass = element;
     _invalidAccessVerifier._enclosingClass = element;
 
@@ -691,8 +691,8 @@
   bool _checkAllTypeChecks(IsExpression node) {
     Expression expression = node.expression;
     TypeAnnotation typeName = node.type;
-    TypeImpl lhsType = expression.staticType;
-    TypeImpl rhsType = typeName.type;
+    var lhsType = expression.staticType as TypeImpl;
+    var rhsType = typeName.type as TypeImpl;
     if (lhsType == null || rhsType == null) {
       return false;
     }
@@ -910,7 +910,7 @@
       return nonFinalFields;
     }
 
-    ClassElement element = node.declaredElement;
+    var element = node.declaredElement as ClassElement;
     if (isOrInheritsImmutable(element, HashSet<ClassElement>())) {
       Iterable<String> nonFinalFields =
           definedOrInheritedNonFinalInstanceFields(
diff --git a/pkg/analyzer/lib/src/error/correct_override.dart b/pkg/analyzer/lib/src/error/correct_override.dart
index 8abb0b4..79dbec0 100644
--- a/pkg/analyzer/lib/src/error/correct_override.dart
+++ b/pkg/analyzer/lib/src/error/correct_override.dart
@@ -189,7 +189,7 @@
   /// Return the [Substitution] to convert types of [superMember] to types of
   /// [_thisMember].
   Substitution _superSubstitution(_SuperMember superMember) {
-    var result = Substitution.fromInterfaceType(superMember.interface);
+    Substitution result = Substitution.fromInterfaceType(superMember.interface);
 
     // If the executable has type parameters, ensure that super uses the same.
     var thisTypeParameters = _thisMember.typeParameters;
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 16eb67e..3c91d82 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -3550,7 +3550,7 @@
   }
 
   @override
-  dynamic internalProblem(Message message, int charOffset, Uri uri) {
+  internalProblem(Message message, int charOffset, Uri uri) {
     throw UnsupportedError(message.message);
   }
 
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index 9cf47f3..f373869 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -163,6 +163,22 @@
       element.name == 'DynamicLibraryExtension' &&
       element.library.name == 'dart.ffi';
 
+  bool _isEmptyStruct(ClassElement classElement) {
+    final fields = classElement.fields;
+    var structFieldCount = 0;
+    for (final field in fields) {
+      final declaredType = field.type;
+      if (declaredType.isDartCoreInt) {
+        structFieldCount++;
+      } else if (declaredType.isDartCoreDouble) {
+        structFieldCount++;
+      } else if (_isPointer(declaredType.element)) {
+        structFieldCount++;
+      }
+    }
+    return structFieldCount == 0;
+  }
+
   bool _isHandle(Element element) =>
       element.name == 'Handle' && element.library.name == 'dart.ffi';
 
@@ -246,12 +262,12 @@
           nativeType.optionalParameterTypes.isNotEmpty) {
         return false;
       }
-      if (!_isValidFfiNativeType(nativeType.returnType, true)) {
+      if (!_isValidFfiNativeType(nativeType.returnType, true, false)) {
         return false;
       }
 
-      for (final DartType typeArg in nativeType.typeArguments) {
-        if (!_isValidFfiNativeType(typeArg, false)) {
+      for (final DartType typeArg in nativeType.normalParameterTypes) {
+        if (!_isValidFfiNativeType(typeArg, false, false)) {
           return false;
         }
       }
@@ -261,7 +277,8 @@
   }
 
   /// Validates that the given [nativeType] is a valid dart:ffi native type.
-  bool _isValidFfiNativeType(DartType nativeType, bool allowVoid) {
+  bool _isValidFfiNativeType(
+      DartType nativeType, bool allowVoid, bool allowEmptyStruct) {
     if (nativeType is InterfaceType) {
       // Is it a primitive integer/double type (or ffi.Void if we allow it).
       final primitiveType = _primitiveNativeType(nativeType);
@@ -274,10 +291,20 @@
       }
       if (_isPointerInterfaceType(nativeType)) {
         final nativeArgumentType = nativeType.typeArguments.single;
-        return _isValidFfiNativeType(nativeArgumentType, true) ||
+        return _isValidFfiNativeType(nativeArgumentType, true, true) ||
             _isStructClass(nativeArgumentType) ||
             _isNativeTypeInterfaceType(nativeArgumentType);
       }
+      if (_isStructClass(nativeType)) {
+        if (!allowEmptyStruct) {
+          if (_isEmptyStruct(nativeType.element)) {
+            // TODO(dartbug.com/36780): This results in an error message not
+            // mentioning empty structs at all.
+            return false;
+          }
+        }
+        return true;
+      }
     } else if (nativeType is FunctionType) {
       return _isValidFfiNativeFunctionType(nativeType);
     }
@@ -533,7 +560,8 @@
     final DartType R = (T as FunctionType).returnType;
     if ((FT as FunctionType).returnType.isVoid ||
         _isPointer(R.element) ||
-        _isHandle(R.element)) {
+        _isHandle(R.element) ||
+        _isStructClass(R)) {
       if (argCount != 1) {
         _errorReporter.reportErrorForNode(
             FfiCode.INVALID_EXCEPTION_VALUE, node.argumentList.arguments[1]);
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index a76eef9..9b05a6f 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -117,7 +117,7 @@
   Token currentToken;
 
   /// The fasta parser being wrapped.
-  final fasta.Parser fastaParser;
+  /*late final*/ fasta.Parser fastaParser;
 
   /// The builder which creates the analyzer AST data structures
   /// based on the Fasta parser.
@@ -125,8 +125,7 @@
 
   Parser(Source source, AnalysisErrorListener errorListener,
       {@required FeatureSet featureSet, bool allowNativeClause = true})
-      : fastaParser = fasta.Parser(null),
-        astBuilder = AstBuilder(
+      : astBuilder = AstBuilder(
             ErrorReporter(
               errorListener,
               source,
@@ -136,7 +135,7 @@
             source.uri,
             true,
             featureSet) {
-    fastaParser.listener = astBuilder;
+    fastaParser = fasta.Parser(astBuilder);
     astBuilder.parser = fastaParser;
     astBuilder.allowNativeClause = allowNativeClause;
   }
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index d6c7ecd..321257f 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -771,26 +771,29 @@
   }
 
   void startNullAwareIndexExpression(IndexExpression node) {
-    if (_migratableAstInfoProvider.isIndexExpressionNullAware(node) &&
-        _flowAnalysis != null) {
-      _flowAnalysis.flow.nullAwareAccess_rightBegin(
-          node.target, node.realTarget.staticType ?? typeProvider.dynamicType);
-      _unfinishedNullShorts.add(node.nullShortingTermination);
+    if (_migratableAstInfoProvider.isIndexExpressionNullAware(node)) {
+      var flow = _flowAnalysis?.flow;
+      if (flow != null) {
+        flow.nullAwareAccess_rightBegin(node.target,
+            node.realTarget.staticType ?? typeProvider.dynamicType);
+        _unfinishedNullShorts.add(node.nullShortingTermination);
+      }
     }
   }
 
-  void startNullAwarePropertyAccess(
-    PropertyAccess node,
-  ) {
-    if (_migratableAstInfoProvider.isPropertyAccessNullAware(node) &&
-        _flowAnalysis != null) {
-      var target = node.target;
-      if (target is SimpleIdentifier && target.staticElement is ClassElement) {
-        // `?.` to access static methods is equivalent to `.`, so do nothing.
-      } else {
-        _flowAnalysis.flow.nullAwareAccess_rightBegin(
-            target, node.realTarget.staticType ?? typeProvider.dynamicType);
-        _unfinishedNullShorts.add(node.nullShortingTermination);
+  void startNullAwarePropertyAccess(PropertyAccess node) {
+    if (_migratableAstInfoProvider.isPropertyAccessNullAware(node)) {
+      var flow = _flowAnalysis?.flow;
+      if (flow != null) {
+        var target = node.target;
+        if (target is SimpleIdentifier &&
+            target.staticElement is ClassElement) {
+          // `?.` to access static methods is equivalent to `.`, so do nothing.
+        } else {
+          flow.nullAwareAccess_rightBegin(
+              target, node.realTarget.staticType ?? typeProvider.dynamicType);
+          _unfinishedNullShorts.add(node.nullShortingTermination);
+        }
       }
     }
   }
@@ -1163,8 +1166,8 @@
     super.visitConstructorDeclaration(node);
 
     if (_flowAnalysis != null) {
-      var bodyContext = BodyInferenceContext.of(node.body);
       if (node.factoryKeyword != null) {
+        var bodyContext = BodyInferenceContext.of(node.body);
         checkForBodyMayCompleteNormally(
           returnType: bodyContext?.contextType,
           body: node.body,
@@ -1468,6 +1471,7 @@
     node.function?.accept(this);
     _functionExpressionInvocationResolver
         .resolve(node as FunctionExpressionInvocationImpl);
+    nullShortingTermination(node);
   }
 
   @override
@@ -1513,7 +1517,7 @@
 
     CollectionElement thenElement = node.thenElement;
     if (_flowAnalysis != null) {
-      _flowAnalysis.flow.ifStatement_thenBegin(condition);
+      _flowAnalysis.flow?.ifStatement_thenBegin(condition);
       thenElement.accept(this);
     } else {
       _promoteManager.visitIfElement_thenElement(
@@ -1553,7 +1557,7 @@
 
     Statement thenStatement = node.thenStatement;
     if (_flowAnalysis != null) {
-      _flowAnalysis.flow.ifStatement_thenBegin(condition);
+      _flowAnalysis.flow?.ifStatement_thenBegin(condition);
       visitStatementInScope(thenStatement);
       nullSafetyDeadCodeVerifier?.flowEnd(thenStatement);
     } else {
@@ -1684,14 +1688,17 @@
     var target = node.target;
     target?.accept(this);
 
-    if (_migratableAstInfoProvider.isMethodInvocationNullAware(node) &&
-        _flowAnalysis != null) {
-      if (target is SimpleIdentifier && target.staticElement is ClassElement) {
-        // `?.` to access static methods is equivalent to `.`, so do nothing.
-      } else {
-        _flowAnalysis.flow.nullAwareAccess_rightBegin(
-            target, node.realTarget.staticType ?? typeProvider.dynamicType);
-        _unfinishedNullShorts.add(node.nullShortingTermination);
+    if (_migratableAstInfoProvider.isMethodInvocationNullAware(node)) {
+      var flow = _flowAnalysis?.flow;
+      if (flow != null) {
+        if (target is SimpleIdentifier &&
+            target.staticElement is ClassElement) {
+          // `?.` to access static methods is equivalent to `.`, so do nothing.
+        } else {
+          flow.nullAwareAccess_rightBegin(
+              target, node.realTarget.staticType ?? typeProvider.dynamicType);
+          _unfinishedNullShorts.add(node.nullShortingTermination);
+        }
       }
     }
 
diff --git a/pkg/analyzer/lib/src/summary2/apply_resolution.dart b/pkg/analyzer/lib/src/summary2/apply_resolution.dart
index ce90149..e254ae4 100644
--- a/pkg/analyzer/lib/src/summary2/apply_resolution.dart
+++ b/pkg/analyzer/lib/src/summary2/apply_resolution.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/resolver/variance.dart';
 import 'package:analyzer/src/exception/exception.dart';
+import 'package:analyzer/src/summary2/ast_binary_flags.dart';
 import 'package:analyzer/src/summary2/ast_binary_tag.dart';
 import 'package:analyzer/src/summary2/bundle_reader.dart';
 import 'package:analyzer/src/summary2/linked_unit_context.dart';
@@ -80,61 +81,92 @@
 
   @override
   void visitAnnotation(Annotation node) {
+    _expectMarker(MarkerTag.Annotation_name);
     node.name.accept(this);
+    _expectMarker(MarkerTag.Annotation_constructorName);
     node.constructorName?.accept(this);
+    _expectMarker(MarkerTag.Annotation_arguments);
     node.arguments?.accept(this);
+    _expectMarker(MarkerTag.Annotation_element);
     node.element = _nextElement();
   }
 
   @override
   void visitArgumentList(ArgumentList node) {
+    _expectMarker(MarkerTag.ArgumentList_arguments);
     node.arguments.accept(this);
+    _expectMarker(MarkerTag.ArgumentList_end);
   }
 
   @override
   void visitAsExpression(AsExpression node) {
+    _expectMarker(MarkerTag.AsExpression_expression);
     node.expression.accept(this);
+    _expectMarker(MarkerTag.AsExpression_type);
     node.type.accept(this);
+    _expectMarker(MarkerTag.AsExpression_expression2);
     _expression(node);
+    _expectMarker(MarkerTag.AsExpression_end);
   }
 
   @override
   void visitAssertInitializer(AssertInitializer node) {
+    _expectMarker(MarkerTag.AssertInitializer_condition);
     node.condition.accept(this);
+    _expectMarker(MarkerTag.AssertInitializer_message);
     node.message?.accept(this);
+    _expectMarker(MarkerTag.AssertInitializer_end);
   }
 
   @override
   void visitAssignmentExpression(AssignmentExpression node) {
     var nodeImpl = node as AssignmentExpressionImpl;
+    _expectMarker(MarkerTag.AssignmentExpression_leftHandSide);
     node.leftHandSide.accept(this);
+    _expectMarker(MarkerTag.AssignmentExpression_rightHandSide);
     node.rightHandSide.accept(this);
+    _expectMarker(MarkerTag.AssignmentExpression_staticElement);
     node.staticElement = _nextElement();
+    _expectMarker(MarkerTag.AssignmentExpression_readElement);
     nodeImpl.readElement = _nextElement();
+    _expectMarker(MarkerTag.AssignmentExpression_readType);
     nodeImpl.readType = _nextType();
+    _expectMarker(MarkerTag.AssignmentExpression_writeElement);
     nodeImpl.writeElement = _nextElement();
+    _expectMarker(MarkerTag.AssignmentExpression_writeType);
     nodeImpl.writeType = _nextType();
+    _expectMarker(MarkerTag.AssignmentExpression_expression);
     _expression(node);
+    _expectMarker(MarkerTag.AssignmentExpression_end);
   }
 
   @override
   void visitBinaryExpression(BinaryExpression node) {
+    _expectMarker(MarkerTag.BinaryExpression_leftOperand);
     node.leftOperand.accept(this);
+    _expectMarker(MarkerTag.BinaryExpression_rightOperand);
     node.rightOperand.accept(this);
 
+    _expectMarker(MarkerTag.BinaryExpression_staticElement);
     node.staticElement = _nextElement();
-    node.staticType = _nextType();
+
+    _expectMarker(MarkerTag.BinaryExpression_expression);
+    _expression(node);
+    _expectMarker(MarkerTag.BinaryExpression_end);
   }
 
   @override
   void visitBooleanLiteral(BooleanLiteral node) {
-    node.staticType = _nextType();
+    _expression(node);
   }
 
   @override
   void visitCascadeExpression(CascadeExpression node) {
+    _expectMarker(MarkerTag.CascadeExpression_target);
     node.target.accept(this);
+    _expectMarker(MarkerTag.CascadeExpression_cascadeSections);
     node.cascadeSections.accept(this);
+    _expectMarker(MarkerTag.CascadeExpression_end);
     node.staticType = node.target.staticType;
   }
 
@@ -147,12 +179,19 @@
     _enclosingElements.add(element);
 
     try {
+      _expectMarker(MarkerTag.ClassDeclaration_typeParameters);
       node.typeParameters?.accept(this);
+      _expectMarker(MarkerTag.ClassDeclaration_extendsClause);
       node.extendsClause?.accept(this);
-      node.nativeClause?.accept(this);
+      _expectMarker(MarkerTag.ClassDeclaration_withClause);
       node.withClause?.accept(this);
+      _expectMarker(MarkerTag.ClassDeclaration_implementsClause);
       node.implementsClause?.accept(this);
+      _expectMarker(MarkerTag.ClassDeclaration_nativeClause);
+      node.nativeClause?.accept(this);
+      _expectMarker(MarkerTag.ClassDeclaration_namedCompilationUnitMember);
       _namedCompilationUnitMember(node);
+      _expectMarker(MarkerTag.ClassDeclaration_end);
     } catch (e, stackTrace) {
       // TODO(scheglov) Remove after fixing http://dartbug.com/44449
       var headerStr = _astCodeBeforeMarkerOrMaxLength(node, '{', 1000);
@@ -176,28 +215,41 @@
     _enclosingElements.add(element);
 
     element.isSimplyBounded = _resolution.readByte() != 0;
+    _expectMarker(MarkerTag.ClassTypeAlias_typeParameters);
     node.typeParameters?.accept(this);
+    _expectMarker(MarkerTag.ClassTypeAlias_superclass);
     node.superclass?.accept(this);
+    _expectMarker(MarkerTag.ClassTypeAlias_withClause);
     node.withClause?.accept(this);
+    _expectMarker(MarkerTag.ClassTypeAlias_implementsClause);
     node.implementsClause?.accept(this);
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.ClassTypeAlias_typeAlias);
+    _typeAlias(node);
+    _expectMarker(MarkerTag.ClassTypeAlias_end);
 
     _enclosingElements.removeLast();
   }
 
   @override
   void visitConditionalExpression(ConditionalExpression node) {
+    _expectMarker(MarkerTag.ConditionalExpression_condition);
     node.condition.accept(this);
+    _expectMarker(MarkerTag.ConditionalExpression_thenExpression);
     node.thenExpression.accept(this);
+    _expectMarker(MarkerTag.ConditionalExpression_elseExpression);
     node.elseExpression.accept(this);
-    node.staticType = _nextType();
+    _expression(node);
   }
 
   @override
   void visitConfiguration(Configuration node) {
+    _expectMarker(MarkerTag.Configuration_name);
     node.name?.accept(this);
+    _expectMarker(MarkerTag.Configuration_value);
     node.value?.accept(this);
+    _expectMarker(MarkerTag.Configuration_uri);
     node.uri?.accept(this);
+    _expectMarker(MarkerTag.Configuration_end);
   }
 
   @override
@@ -209,16 +261,22 @@
     _enclosingElements.add(element.enclosingElement);
     _enclosingElements.add(element);
 
+    _expectMarker(MarkerTag.ConstructorDeclaration_returnType);
     node.returnType?.accept(this);
+    _expectMarker(MarkerTag.ConstructorDeclaration_parameters);
     node.parameters?.accept(this);
 
     for (var parameter in node.parameters.parameters) {
       _localElements.add(parameter.declaredElement);
     }
 
+    _expectMarker(MarkerTag.ConstructorDeclaration_initializers);
     node.initializers?.accept(this);
+    _expectMarker(MarkerTag.ConstructorDeclaration_redirectedConstructor);
     node.redirectedConstructor?.accept(this);
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.ConstructorDeclaration_classMember);
+    _classMember(node);
+    _expectMarker(MarkerTag.ConstructorDeclaration_end);
 
     _enclosingElements.removeLast();
     _enclosingElements.removeLast();
@@ -226,8 +284,11 @@
 
   @override
   void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+    _expectMarker(MarkerTag.ConstructorFieldInitializer_fieldName);
     node.fieldName.accept(this);
+    _expectMarker(MarkerTag.ConstructorFieldInitializer_expression);
     node.expression.accept(this);
+    _expectMarker(MarkerTag.ConstructorFieldInitializer_end);
   }
 
   @override
@@ -252,16 +313,24 @@
       node.name = typeName.identifier;
     }
 
+    _expectMarker(MarkerTag.ConstructorName_type);
     node.type.accept(this);
+    _expectMarker(MarkerTag.ConstructorName_name);
     node.name?.accept(this);
+    _expectMarker(MarkerTag.ConstructorName_staticElement);
     node.staticElement = _nextElement();
+    _expectMarker(MarkerTag.ConstructorName_end);
   }
 
   @override
   void visitDeclaredIdentifier(DeclaredIdentifier node) {
+    _expectMarker(MarkerTag.DeclaredIdentifier_type);
     node.type?.accept(this);
+    _expectMarker(MarkerTag.DeclaredIdentifier_identifier);
     // node.identifier.accept(this);
+    _expectMarker(MarkerTag.DeclaredIdentifier_declaration);
     _declaration(node);
+    _expectMarker(MarkerTag.DeclaredIdentifier_end);
   }
 
   @override
@@ -285,8 +354,11 @@
     var summaryData = nodeImpl.summaryData as SummaryDataForFormalParameter;
     element.setCodeRange(summaryData.codeOffset, summaryData.codeLength);
 
+    _expectMarker(MarkerTag.DefaultFormalParameter_parameter);
     node.parameter.accept(this);
+    _expectMarker(MarkerTag.DefaultFormalParameter_defaultValue);
     node.defaultValue?.accept(this);
+    _expectMarker(MarkerTag.DefaultFormalParameter_end);
   }
 
   @override
@@ -301,19 +373,28 @@
 
   @override
   void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.EnumConstantDeclaration_name);
+    _expectMarker(MarkerTag.EnumConstantDeclaration_declaration);
+    _declaration(node);
+    _expectMarker(MarkerTag.EnumConstantDeclaration_end);
   }
 
   @override
   void visitEnumDeclaration(EnumDeclaration node) {
+    _expectMarker(MarkerTag.EnumDeclaration_constants);
     node.constants.accept(this);
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.EnumDeclaration_namedCompilationUnitMember);
+    _namedCompilationUnitMember(node);
+    _expectMarker(MarkerTag.EnumDeclaration_end);
   }
 
   @override
   void visitExportDirective(ExportDirective node) {
+    _expectMarker(MarkerTag.ExportDirective_namespaceDirective);
     _namespaceDirective(node);
+    _expectMarker(MarkerTag.ExportDirective_exportedLibrary);
     (node.element as ExportElementImpl).exportedLibrary = _nextElement();
+    _expectMarker(MarkerTag.ExportDirective_end);
   }
 
   @override
@@ -323,7 +404,9 @@
 
   @override
   visitExtendsClause(ExtendsClause node) {
+    _expectMarker(MarkerTag.ExtendsClause_superclass);
     node.superclass.accept(this);
+    _expectMarker(MarkerTag.ExtendsClause_end);
   }
 
   @override
@@ -333,9 +416,13 @@
     var element = node.declaredElement as ExtensionElementImpl;
     _enclosingElements.add(element);
 
+    _expectMarker(MarkerTag.ExtensionDeclaration_typeParameters);
     node.typeParameters?.accept(this);
+    _expectMarker(MarkerTag.ExtensionDeclaration_extendedType);
     node.extendedType?.accept(this);
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.ExtensionDeclaration_compilationUnitMember);
+    _compilationUnitMember(node);
+    _expectMarker(MarkerTag.ExtensionDeclaration_end);
 
     _enclosingElements.removeLast();
   }
@@ -351,10 +438,15 @@
       _resolution.readByte();
     }
 
+    _expectMarker(MarkerTag.ExtensionOverride_extensionName);
     node.extensionName.accept(this);
+    _expectMarker(MarkerTag.ExtensionOverride_typeArguments);
     node.typeArguments?.accept(this);
+    _expectMarker(MarkerTag.ExtensionOverride_argumentList);
     node.argumentList.accept(this);
+    _expectMarker(MarkerTag.ExtensionOverride_extendedType);
     (node as ExtensionOverrideImpl).extendedType = _nextType();
+    _expectMarker(MarkerTag.ExtensionOverride_end);
     // TODO(scheglov) typeArgumentTypes?
   }
 
@@ -363,8 +455,11 @@
     _assertNoLocalElements();
     _pushEnclosingClassTypeParameters(node);
 
+    _expectMarker(MarkerTag.FieldDeclaration_fields);
     node.fields.accept(this);
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.FieldDeclaration_classMember);
+    _classMember(node);
+    _expectMarker(MarkerTag.FieldDeclaration_end);
   }
 
   @override
@@ -378,29 +473,42 @@
 
     var localElementsLength = _localElements.length;
 
+    _expectMarker(MarkerTag.FieldFormalParameter_typeParameters);
     node.typeParameters?.accept(this);
+    _expectMarker(MarkerTag.FieldFormalParameter_type);
     node.type?.accept(this);
+    _expectMarker(MarkerTag.FieldFormalParameter_parameters);
     node.parameters?.accept(this);
+    _expectMarker(MarkerTag.FieldFormalParameter_normalFormalParameter);
     _normalFormalParameter(node, element);
+    _expectMarker(MarkerTag.FieldFormalParameter_end);
 
     _localElements.length = localElementsLength;
   }
 
   @override
   void visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
+    _expectMarker(MarkerTag.ForEachPartsWithDeclaration_loopVariable);
     node.loopVariable.accept(this);
+    _expectMarker(MarkerTag.ForEachPartsWithDeclaration_forEachParts);
     _forEachParts(node);
+    _expectMarker(MarkerTag.ForEachPartsWithDeclaration_end);
   }
 
   @override
   void visitForElement(ForElement node) {
+    _expectMarker(MarkerTag.ForElement_body);
     node.body.accept(this);
-    node.forLoopParts.accept(this);
+    _expectMarker(MarkerTag.ForElement_forMixin);
+    _forMixin(node as ForElementImpl);
+    _expectMarker(MarkerTag.ForElement_end);
   }
 
   @override
   visitFormalParameterList(FormalParameterList node) {
+    _expectMarker(MarkerTag.FormalParameterList_parameters);
     node.parameters.accept(this);
+    _expectMarker(MarkerTag.FormalParameterList_end);
   }
 
   @override
@@ -412,8 +520,11 @@
         nameNode.offset,
       );
     }
+    _expectMarker(MarkerTag.ForPartsWithDeclarations_variables);
     node.variables.accept(this);
+    _expectMarker(MarkerTag.ForPartsWithDeclarations_forParts);
     _forParts(node);
+    _expectMarker(MarkerTag.ForPartsWithDeclarations_end);
   }
 
   @override
@@ -425,17 +536,25 @@
 
     _enclosingElements.add(element);
 
+    _expectMarker(MarkerTag.FunctionDeclaration_functionExpression);
     node.functionExpression.accept(this);
+    _expectMarker(MarkerTag.FunctionDeclaration_returnType);
     node.returnType?.accept(this);
 
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.FunctionDeclaration_namedCompilationUnitMember);
+    _namedCompilationUnitMember(node);
+    _expectMarker(MarkerTag.FunctionDeclaration_returnTypeType);
     element.returnType = _nextType();
+    _expectMarker(MarkerTag.FunctionDeclaration_end);
   }
 
   @override
   void visitFunctionExpression(FunctionExpression node) {
+    _expectMarker(MarkerTag.FunctionExpression_typeParameters);
     node.typeParameters?.accept(this);
+    _expectMarker(MarkerTag.FunctionExpression_parameters);
     node.parameters?.accept(this);
+    _expectMarker(MarkerTag.FunctionExpression_end);
   }
 
   @override
@@ -449,8 +568,11 @@
       _resolution.readByte();
     }
 
+    _expectMarker(MarkerTag.FunctionExpressionInvocation_function);
     node.function.accept(this);
+    _expectMarker(MarkerTag.FunctionExpressionInvocation_invocationExpression);
     _invocationExpression(node);
+    _expectMarker(MarkerTag.FunctionExpressionInvocation_end);
   }
 
   @override
@@ -460,18 +582,25 @@
     var element = node.declaredElement as FunctionTypeAliasElementImpl;
     _enclosingElements.add(element);
 
+    _expectMarker(MarkerTag.FunctionTypeAlias_typeParameters);
     node.typeParameters?.accept(this);
 
     _enclosingElements.add(element.function);
+    _expectMarker(MarkerTag.FunctionTypeAlias_returnType);
     node.returnType?.accept(this);
+    _expectMarker(MarkerTag.FunctionTypeAlias_parameters);
     node.parameters?.accept(this);
     _enclosingElements.removeLast();
 
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.FunctionTypeAlias_typeAlias);
+    _typeAlias(node);
 
+    _expectMarker(MarkerTag.FunctionTypeAlias_returnTypeType);
     element.function.returnType = _nextType();
+    _expectMarker(MarkerTag.FunctionTypeAlias_flags);
     element.isSimplyBounded = _resolution.readByte() != 0;
     element.hasSelfReference = _resolution.readByte() != 0;
+    _expectMarker(MarkerTag.FunctionTypeAlias_end);
 
     _enclosingElements.removeLast();
   }
@@ -487,10 +616,15 @@
 
     var localElementsLength = _localElements.length;
 
+    _expectMarker(MarkerTag.FunctionTypedFormalParameter_typeParameters);
     node.typeParameters?.accept(this);
+    _expectMarker(MarkerTag.FunctionTypedFormalParameter_returnType);
     node.returnType?.accept(this);
+    _expectMarker(MarkerTag.FunctionTypedFormalParameter_parameters);
     node.parameters?.accept(this);
+    _expectMarker(MarkerTag.FunctionTypedFormalParameter_normalFormalParameter);
     _normalFormalParameter(node, element);
+    _expectMarker(MarkerTag.FunctionTypedFormalParameter_end);
 
     _localElements.length = localElementsLength;
   }
@@ -505,10 +639,15 @@
         _enclosingElements.last, null, node);
     _enclosingElements.add(element);
 
+    _expectMarker(MarkerTag.GenericFunctionType_typeParameters);
     node.typeParameters?.accept(this);
+    _expectMarker(MarkerTag.GenericFunctionType_returnType);
     node.returnType?.accept(this);
+    _expectMarker(MarkerTag.GenericFunctionType_parameters);
     node.parameters?.accept(this);
+    _expectMarker(MarkerTag.GenericFunctionType_type);
     nodeImpl.type = _nextType();
+    _expectMarker(MarkerTag.GenericFunctionType_end);
 
     _localElements.length = localElementsLength;
     _enclosingElements.removeLast();
@@ -523,11 +662,16 @@
 
     _enclosingElements.add(element);
 
+    _expectMarker(MarkerTag.GenericTypeAlias_typeParameters);
     node.typeParameters?.accept(this);
+    _expectMarker(MarkerTag.GenericTypeAlias_type);
     node.type?.accept(this);
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.GenericTypeAlias_typeAlias);
+    _typeAlias(node);
+    _expectMarker(MarkerTag.GenericTypeAlias_flags);
     element.isSimplyBounded = _resolution.readByte() != 0;
     element.hasSelfReference = _resolution.readByte() != 0;
+    _expectMarker(MarkerTag.GenericTypeAlias_end);
 
     _enclosingElements.removeLast();
   }
@@ -539,30 +683,45 @@
 
   @override
   void visitIfElement(IfElement node) {
+    _expectMarker(MarkerTag.IfElement_condition);
     node.condition.accept(this);
+    _expectMarker(MarkerTag.IfElement_thenElement);
     node.thenElement.accept(this);
+    _expectMarker(MarkerTag.IfElement_elseElement);
     node.elseElement?.accept(this);
+    _expectMarker(MarkerTag.IfElement_end);
   }
 
   @override
   visitImplementsClause(ImplementsClause node) {
+    _expectMarker(MarkerTag.ImplementsClause_interfaces);
     node.interfaces.accept(this);
+    _expectMarker(MarkerTag.ImplementsClause_end);
   }
 
   @override
   void visitImportDirective(ImportDirective node) {
+    _expectMarker(MarkerTag.ImportDirective_namespaceDirective);
     _namespaceDirective(node);
 
     var element = node.element as ImportElementImpl;
+    _expectMarker(MarkerTag.ImportDirective_importedLibrary);
     element.importedLibrary = _nextElement();
+
+    _expectMarker(MarkerTag.ImportDirective_end);
   }
 
   @override
   void visitIndexExpression(IndexExpression node) {
+    _expectMarker(MarkerTag.IndexExpression_target);
     node.target?.accept(this);
+    _expectMarker(MarkerTag.IndexExpression_index);
     node.index.accept(this);
+    _expectMarker(MarkerTag.IndexExpression_staticElement);
     node.staticElement = _nextElement();
+    _expectMarker(MarkerTag.IndexExpression_expression);
     _expression(node);
+    _expectMarker(MarkerTag.IndexExpression_end);
   }
 
   @override
@@ -576,10 +735,13 @@
       _resolution.readByte();
     }
 
+    _expectMarker(MarkerTag.InstanceCreationExpression_constructorName);
     node.constructorName.accept(this);
-    (node as InstanceCreationExpressionImpl).typeArguments?.accept(this);
+    _expectMarker(MarkerTag.InstanceCreationExpression_argumentList);
     node.argumentList.accept(this);
-    node.staticType = _nextType();
+    _expectMarker(MarkerTag.InstanceCreationExpression_expression);
+    _expression(node);
+    _expectMarker(MarkerTag.InstanceCreationExpression_end);
     _resolveNamedExpressions(
       node.constructorName.staticElement,
       node.argumentList,
@@ -588,7 +750,7 @@
 
   @override
   void visitIntegerLiteral(IntegerLiteral node) {
-    node.staticType = _nextType();
+    _expression(node);
   }
 
   @override
@@ -603,9 +765,13 @@
 
   @override
   void visitIsExpression(IsExpression node) {
+    _expectMarker(MarkerTag.IsExpression_expression);
     node.expression.accept(this);
+    _expectMarker(MarkerTag.IsExpression_type);
     node.type.accept(this);
+    _expectMarker(MarkerTag.IsExpression_expression2);
     _expression(node);
+    _expectMarker(MarkerTag.IsExpression_end);
   }
 
   @override
@@ -621,14 +787,20 @@
 
   @override
   void visitListLiteral(ListLiteral node) {
+    _expectMarker(MarkerTag.ListLiteral_typeArguments);
     node.typeArguments?.accept(this);
+    _expectMarker(MarkerTag.ListLiteral_elements);
     node.elements.accept(this);
-    node.staticType = _nextType();
+    _expectMarker(MarkerTag.ListLiteral_expression);
+    _expression(node);
+    _expectMarker(MarkerTag.ListLiteral_end);
   }
 
   @override
   void visitMapLiteralEntry(MapLiteralEntry node) {
+    _expectMarker(MarkerTag.MapLiteralEntry_key);
     node.key.accept(this);
+    _expectMarker(MarkerTag.MapLiteralEntry_value);
     node.value.accept(this);
   }
 
@@ -642,17 +814,25 @@
     _enclosingElements.add(element);
 
     try {
+      _expectMarker(MarkerTag.MethodDeclaration_typeParameters);
       node.typeParameters?.accept(this);
+      _expectMarker(MarkerTag.MethodDeclaration_returnType);
       node.returnType?.accept(this);
+      _expectMarker(MarkerTag.MethodDeclaration_parameters);
       node.parameters?.accept(this);
-      node.metadata?.accept(this);
+      _expectMarker(MarkerTag.MethodDeclaration_classMember);
+      _classMember(node);
 
+      _expectMarker(MarkerTag.MethodDeclaration_returnTypeType);
       element.returnType = _nextType();
+      _expectMarker(MarkerTag.MethodDeclaration_inferenceError);
       _setTopLevelInferenceError(element);
       if (element is MethodElementImpl) {
+        _expectMarker(MarkerTag.MethodDeclaration_flags);
         element.isOperatorEqualWithParameterTypeFromObject =
             _resolution.readByte() != 0;
       }
+      _expectMarker(MarkerTag.MethodDeclaration_end);
     } catch (e, stackTrace) {
       // TODO(scheglov) Remove after fixing http://dartbug.com/44449
       var headerStr = _astCodeBeforeMarkerOrMaxLength(node, '{', 1000);
@@ -754,9 +934,13 @@
       throw StateError('[rewriteTag: $rewriteTag][node: $node]');
     }
 
+    _expectMarker(MarkerTag.MethodInvocation_target);
     node.target?.accept(this);
+    _expectMarker(MarkerTag.MethodInvocation_methodName);
     node.methodName.accept(this);
+    _expectMarker(MarkerTag.MethodInvocation_invocationExpression);
     _invocationExpression(node);
+    _expectMarker(MarkerTag.MethodInvocation_end);
   }
 
   @override
@@ -767,22 +951,31 @@
     element.superInvokedNames = _resolution.readStringList();
     _enclosingElements.add(element);
 
+    _expectMarker(MarkerTag.MixinDeclaration_typeParameters);
     node.typeParameters?.accept(this);
+    _expectMarker(MarkerTag.MixinDeclaration_onClause);
     node.onClause?.accept(this);
+    _expectMarker(MarkerTag.MixinDeclaration_implementsClause);
     node.implementsClause?.accept(this);
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.MixinDeclaration_namedCompilationUnitMember);
+    _namedCompilationUnitMember(node);
+    _expectMarker(MarkerTag.MixinDeclaration_end);
 
     _enclosingElements.removeLast();
   }
 
   @override
   void visitNamedExpression(NamedExpression node) {
+    _expectMarker(MarkerTag.NamedExpression_expression);
     node.expression.accept(this);
+    _expectMarker(MarkerTag.NamedExpression_end);
   }
 
   @override
   void visitNativeClause(NativeClause node) {
+    _expectMarker(MarkerTag.NativeClause_name);
     node.name.accept(this);
+    _expectMarker(MarkerTag.NativeClause_end);
   }
 
   @override
@@ -792,13 +985,18 @@
 
   @override
   void visitOnClause(OnClause node) {
+    _expectMarker(MarkerTag.OnClause_superclassConstraints);
     node.superclassConstraints.accept(this);
+    _expectMarker(MarkerTag.OnClause_end);
   }
 
   @override
   void visitParenthesizedExpression(ParenthesizedExpression node) {
+    _expectMarker(MarkerTag.ParenthesizedExpression_expression);
     node.expression.accept(this);
-    node.staticType = _nextType();
+    _expectMarker(MarkerTag.ParenthesizedExpression_expression2);
+    _expression(node);
+    _expectMarker(MarkerTag.ParenthesizedExpression_end);
   }
 
   @override
@@ -808,64 +1006,98 @@
 
   @override
   void visitPartOfDirective(PartOfDirective node) {
+    _expectMarker(MarkerTag.PartOfDirective_libraryName);
+    node.libraryName?.accept(this);
+    _expectMarker(MarkerTag.PartOfDirective_uri);
     node.uri?.accept(this);
+    _expectMarker(MarkerTag.PartOfDirective_directive);
     _directive(node);
+    _expectMarker(MarkerTag.PartOfDirective_end);
   }
 
   @override
   void visitPostfixExpression(PostfixExpression node) {
     var nodeImpl = node as PostfixExpressionImpl;
+    _expectMarker(MarkerTag.PostfixExpression_operand);
     node.operand.accept(this);
+    _expectMarker(MarkerTag.PostfixExpression_staticElement);
     node.staticElement = _nextElement();
     if (node.operator.type.isIncrementOperator) {
+      _expectMarker(MarkerTag.PostfixExpression_readElement);
       nodeImpl.readElement = _nextElement();
+      _expectMarker(MarkerTag.PostfixExpression_readType);
       nodeImpl.readType = _nextType();
+      _expectMarker(MarkerTag.PostfixExpression_writeElement);
       nodeImpl.writeElement = _nextElement();
+      _expectMarker(MarkerTag.PostfixExpression_writeType);
       nodeImpl.writeType = _nextType();
     }
+    _expectMarker(MarkerTag.PostfixExpression_expression);
     _expression(node);
+    _expectMarker(MarkerTag.PostfixExpression_end);
   }
 
   @override
   void visitPrefixedIdentifier(PrefixedIdentifier node) {
+    _expectMarker(MarkerTag.PrefixedIdentifier_prefix);
     node.prefix.accept(this);
+    _expectMarker(MarkerTag.PrefixedIdentifier_identifier);
     node.identifier.accept(this);
+    _expectMarker(MarkerTag.PrefixedIdentifier_expression);
     _expression(node);
+    _expectMarker(MarkerTag.PrefixedIdentifier_end);
   }
 
   @override
   void visitPrefixExpression(PrefixExpression node) {
     var nodeImpl = node as PrefixExpressionImpl;
+    _expectMarker(MarkerTag.PrefixExpression_operand);
     node.operand.accept(this);
+    _expectMarker(MarkerTag.PrefixExpression_staticElement);
     node.staticElement = _nextElement();
     if (node.operator.type.isIncrementOperator) {
+      _expectMarker(MarkerTag.PrefixExpression_readElement);
       nodeImpl.readElement = _nextElement();
+      _expectMarker(MarkerTag.PrefixExpression_readType);
       nodeImpl.readType = _nextType();
+      _expectMarker(MarkerTag.PrefixExpression_writeElement);
       nodeImpl.writeElement = _nextElement();
+      _expectMarker(MarkerTag.PrefixExpression_writeType);
       nodeImpl.writeType = _nextType();
     }
+    _expectMarker(MarkerTag.PrefixExpression_expression);
     _expression(node);
+    _expectMarker(MarkerTag.PrefixExpression_end);
   }
 
   @override
   void visitPropertyAccess(PropertyAccess node) {
+    _expectMarker(MarkerTag.PropertyAccess_target);
     node.target?.accept(this);
+    _expectMarker(MarkerTag.PropertyAccess_propertyName);
     node.propertyName.accept(this);
 
-    node.staticType = _nextType();
+    _expectMarker(MarkerTag.PropertyAccess_expression);
+    _expression(node);
+    _expectMarker(MarkerTag.PropertyAccess_end);
   }
 
   @override
   void visitRedirectingConstructorInvocation(
       RedirectingConstructorInvocation node) {
+    _expectMarker(MarkerTag.RedirectingConstructorInvocation_constructorName);
     node.constructorName?.accept(this);
+    _expectMarker(MarkerTag.RedirectingConstructorInvocation_argumentList);
     node.argumentList.accept(this);
+    _expectMarker(MarkerTag.RedirectingConstructorInvocation_staticElement);
     node.staticElement = _nextElement();
     _resolveNamedExpressions(node.staticElement, node.argumentList);
+    _expectMarker(MarkerTag.RedirectingConstructorInvocation_end);
   }
 
   @override
   void visitSetOrMapLiteral(SetOrMapLiteral node) {
+    _expectMarker(MarkerTag.SetOrMapLiteral_flags);
     var mapOrSetBits = _resolution.readByte();
     if ((mapOrSetBits & 0x01) != 0) {
       (node as SetOrMapLiteralImpl).becomeMap();
@@ -873,9 +1105,13 @@
       (node as SetOrMapLiteralImpl).becomeSet();
     }
 
+    _expectMarker(MarkerTag.SetOrMapLiteral_typeArguments);
     node.typeArguments?.accept(this);
+    _expectMarker(MarkerTag.SetOrMapLiteral_elements);
     node.elements.accept(this);
-    node.staticType = _nextType();
+    _expectMarker(MarkerTag.SetOrMapLiteral_expression);
+    _expression(node);
+    _expectMarker(MarkerTag.SetOrMapLiteral_end);
   }
 
   @override
@@ -892,16 +1128,23 @@
           ParameterElementImpl.forLinkedNodeFactory(enclosing, null, node);
     }
 
+    _expectMarker(MarkerTag.SimpleFormalParameter_type);
     node.type?.accept(this);
+    _expectMarker(MarkerTag.SimpleFormalParameter_normalFormalParameter);
     _normalFormalParameter(node, element);
 
+    _expectMarker(MarkerTag.SimpleFormalParameter_flags);
     element.inheritsCovariant = _resolution.readByte() != 0;
+    _expectMarker(MarkerTag.SimpleFormalParameter_end);
   }
 
   @override
   visitSimpleIdentifier(SimpleIdentifier node) {
+    _expectMarker(MarkerTag.SimpleIdentifier_staticElement);
     node.staticElement = _nextElement();
-    node.staticType = _nextType();
+    _expectMarker(MarkerTag.SimpleIdentifier_expression);
+    _expression(node);
+    _expectMarker(MarkerTag.SimpleIdentifier_end);
   }
 
   @override
@@ -911,61 +1154,86 @@
 
   @override
   void visitSpreadElement(SpreadElement node) {
+    _expectMarker(MarkerTag.SpreadElement_expression);
     node.expression.accept(this);
+    _expectMarker(MarkerTag.SpreadElement_end);
   }
 
   @override
   void visitStringInterpolation(StringInterpolation node) {
+    _expectMarker(MarkerTag.StringInterpolation_elements);
     node.elements.accept(this);
+    _expectMarker(MarkerTag.StringInterpolation_end);
     // TODO(scheglov) type?
   }
 
   @override
   void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+    _expectMarker(MarkerTag.SuperConstructorInvocation_constructorName);
     node.constructorName?.accept(this);
+    _expectMarker(MarkerTag.SuperConstructorInvocation_argumentList);
     node.argumentList.accept(this);
+    _expectMarker(MarkerTag.SuperConstructorInvocation_staticElement);
     node.staticElement = _nextElement();
     _resolveNamedExpressions(node.staticElement, node.argumentList);
+    _expectMarker(MarkerTag.SuperConstructorInvocation_end);
   }
 
   @override
   void visitSuperExpression(SuperExpression node) {
-    node.staticType = _nextType();
+    _expectMarker(MarkerTag.SuperExpression_expression);
+    _expression(node);
+    _expectMarker(MarkerTag.SuperExpression_end);
   }
 
   @override
   void visitSymbolLiteral(SymbolLiteral node) {
-    node.staticType = _nextType();
+    _expression(node);
   }
 
   @override
   void visitThisExpression(ThisExpression node) {
-    node.staticType = _nextType();
+    _expectMarker(MarkerTag.ThisExpression_expression);
+    _expression(node);
+    _expectMarker(MarkerTag.ThisExpression_end);
   }
 
   @override
   void visitThrowExpression(ThrowExpression node) {
+    _expectMarker(MarkerTag.ThrowExpression_expression);
     node.expression.accept(this);
-    node.staticType = _nextType();
+    _expectMarker(MarkerTag.ThrowExpression_expression2);
+    _expression(node);
+    _expectMarker(MarkerTag.ThrowExpression_end);
   }
 
   @override
   void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+    _expectMarker(MarkerTag.TopLevelVariableDeclaration_variables);
     node.variables.accept(this);
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.TopLevelVariableDeclaration_compilationUnitMember);
+    _compilationUnitMember(node);
+    _expectMarker(MarkerTag.TopLevelVariableDeclaration_end);
   }
 
   @override
   visitTypeArgumentList(TypeArgumentList node) {
+    _expectMarker(MarkerTag.TypeArgumentList_arguments);
     node.arguments?.accept(this);
+    _expectMarker(MarkerTag.TypeArgumentList_end);
   }
 
   @override
   visitTypeName(TypeName node) {
+    _expectMarker(MarkerTag.TypeName_name);
     node.name.accept(this);
+    _expectMarker(MarkerTag.TypeName_typeArguments);
     node.typeArguments?.accept(this);
 
+    _expectMarker(MarkerTag.TypeName_type);
     node.type = _nextType();
+
+    _expectMarker(MarkerTag.TypeName_end);
   }
 
   @override
@@ -978,6 +1246,7 @@
       _localElements.add(element);
     }
 
+    _expectMarker(MarkerTag.TypeParameterList_typeParameters);
     for (var node in node.typeParameters) {
       var nodeImpl = node as TypeParameterImpl;
       var element = node.declaredElement as TypeParameterElementImpl;
@@ -985,17 +1254,22 @@
       var summaryData = nodeImpl.summaryData as SummaryDataForTypeParameter;
       element.setCodeRange(summaryData.codeOffset, summaryData.codeLength);
 
+      _expectMarker(MarkerTag.TypeParameter_bound);
       node.bound?.accept(this);
       element.bound = node.bound?.type;
 
-      node.metadata.accept(this);
+      _expectMarker(MarkerTag.TypeParameter_declaration);
+      _declaration(node);
       element.metadata = _buildAnnotations(
         _unitContext.element,
         node.metadata,
       );
 
+      _expectMarker(MarkerTag.TypeParameter_variance);
       element.variance = _decodeVariance(_resolution.readByte());
+      _expectMarker(MarkerTag.TypeParameter_defaultType);
       element.defaultType = _nextType();
+      _expectMarker(MarkerTag.TypeParameter_end);
 
       // TODO(scheglov) We used to do this with the previous elements impl.
       // We probably still do this.
@@ -1025,34 +1299,48 @@
         }
       }
     }
+    _expectMarker(MarkerTag.TypeParameterList_end);
   }
 
   @override
   void visitVariableDeclaration(VariableDeclaration node) {
     var element = node.declaredElement as VariableElementImpl;
+    _expectMarker(MarkerTag.VariableDeclaration_type);
     element.type = _nextType();
+    _expectMarker(MarkerTag.VariableDeclaration_inferenceError);
     _setTopLevelInferenceError(element);
     if (element is FieldElementImpl) {
+      _expectMarker(MarkerTag.VariableDeclaration_inheritsCovariant);
       element.inheritsCovariant = _resolution.readByte() != 0;
     }
 
+    _expectMarker(MarkerTag.VariableDeclaration_initializer);
     node.initializer?.accept(this);
+    _expectMarker(MarkerTag.VariableDeclaration_end);
   }
 
   @override
   void visitVariableDeclarationList(VariableDeclarationList node) {
+    _expectMarker(MarkerTag.VariableDeclarationList_type);
     node.type?.accept(this);
+    _expectMarker(MarkerTag.VariableDeclarationList_variables);
     node.variables.accept(this);
-    node.metadata?.accept(this);
+    _expectMarker(MarkerTag.VariableDeclarationList_annotatedNode);
+    _annotatedNode(node);
+    _expectMarker(MarkerTag.VariableDeclarationList_end);
   }
 
   @override
   void visitWithClause(WithClause node) {
+    _expectMarker(MarkerTag.WithClause_mixinTypes);
     node.mixinTypes.accept(this);
+    _expectMarker(MarkerTag.WithClause_end);
   }
 
   void _annotatedNode(AnnotatedNode node) {
+    _expectMarker(MarkerTag.AnnotatedNode_metadata);
     node.metadata?.accept(this);
+    _expectMarker(MarkerTag.AnnotatedNode_end);
   }
 
   void _assertNoLocalElements() {
@@ -1079,6 +1367,11 @@
     return annotations;
   }
 
+  void _classMember(ClassMember node) {
+    _expectMarker(MarkerTag.ClassMember_declaration);
+    _declaration(node);
+  }
+
   void _compilationUnitMember(CompilationUnitMember node) {
     _declaration(node);
   }
@@ -1088,34 +1381,66 @@
   }
 
   void _directive(Directive node) {
-    node.metadata?.accept(this);
+    _annotatedNode(node);
+  }
+
+  void _expectMarker(MarkerTag tag) {
+    if (enableDebugResolutionMarkers) {
+      var actualIndex = _resolution.readUInt30();
+      if (actualIndex != tag.index) {
+        if (actualIndex < MarkerTag.values.length) {
+          var actualTag = MarkerTag.values[actualIndex];
+          throw StateError('Expected $tag, found $actualIndex = $actualTag');
+        } else {
+          throw StateError('Expected $tag, found $actualIndex');
+        }
+      }
+    }
   }
 
   void _expression(Expression node) {
+    _expectMarker(MarkerTag.Expression_staticType);
     node.staticType = _nextType();
   }
 
   void _forEachParts(ForEachParts node) {
-    _forLoopParts(node);
+    _expectMarker(MarkerTag.ForEachParts_iterable);
     node.iterable.accept(this);
+    _expectMarker(MarkerTag.ForEachParts_forLoopParts);
+    _forLoopParts(node);
+    _expectMarker(MarkerTag.ForEachParts_end);
   }
 
   void _forLoopParts(ForLoopParts node) {}
 
   void _formalParameter(FormalParameter node) {
+    _expectMarker(MarkerTag.FormalParameter_type);
     (node.declaredElement as ParameterElementImpl).type = _nextType();
   }
 
+  void _forMixin(ForMixin node) {
+    _expectMarker(MarkerTag.ForMixin_forLoopParts);
+    node.forLoopParts.accept(this);
+  }
+
   void _forParts(ForParts node) {
+    _expectMarker(MarkerTag.ForParts_condition);
     node.condition?.accept(this);
+    _expectMarker(MarkerTag.ForParts_updaters);
     node.updaters.accept(this);
+    _expectMarker(MarkerTag.ForParts_forLoopParts);
     _forLoopParts(node);
+    _expectMarker(MarkerTag.ForParts_end);
   }
 
   void _invocationExpression(InvocationExpression node) {
+    _expectMarker(MarkerTag.InvocationExpression_typeArguments);
     node.typeArguments?.accept(this);
+    _expectMarker(MarkerTag.InvocationExpression_argumentList);
     node.argumentList.accept(this);
+    _expectMarker(MarkerTag.InvocationExpression_expression);
     _expression(node);
+    _expectMarker(MarkerTag.InvocationExpression_end);
     // TODO(scheglov) typeArgumentTypes and staticInvokeType?
     var nodeImpl = node as InvocationExpressionImpl;
     nodeImpl.typeArgumentTypes = [];
@@ -1126,9 +1451,13 @@
   }
 
   void _namespaceDirective(NamespaceDirective node) {
+    _expectMarker(MarkerTag.NamespaceDirective_combinators);
     node.combinators?.accept(this);
+    _expectMarker(MarkerTag.NamespaceDirective_configurations);
     node.configurations?.accept(this);
+    _expectMarker(MarkerTag.NamespaceDirective_uriBasedDirective);
     _uriBasedDirective(node);
+    _expectMarker(MarkerTag.NamespaceDirective_end);
   }
 
   Element _nextElement() {
@@ -1149,8 +1478,11 @@
       element.setCodeRange(summaryData.codeOffset, summaryData.codeLength);
     }
 
+    _expectMarker(MarkerTag.NormalFormalParameter_metadata);
     node.metadata?.accept(this);
+    _expectMarker(MarkerTag.NormalFormalParameter_formalParameter);
     _formalParameter(node);
+    _expectMarker(MarkerTag.NormalFormalParameter_end);
   }
 
   /// TODO(scheglov) also enclosing elements
@@ -1204,9 +1536,16 @@
     }
   }
 
+  void _typeAlias(TypeAlias node) {
+    _namedCompilationUnitMember(node);
+  }
+
   void _uriBasedDirective(UriBasedDirective node) {
-    _directive(node);
+    _expectMarker(MarkerTag.UriBasedDirective_uri);
     node.uri.accept(this);
+    _expectMarker(MarkerTag.UriBasedDirective_directive);
+    _directive(node);
+    _expectMarker(MarkerTag.UriBasedDirective_end);
   }
 
   /// TODO(scheglov) Remove after fixing http://dartbug.com/44449
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_flags.dart b/pkg/analyzer/lib/src/summary2/ast_binary_flags.dart
index 9bdefc7..4c23e9f 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_flags.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_flags.dart
@@ -4,6 +4,17 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 
+/// When this option enabled, when we write AST and resolution, we write
+/// into markers into the resolution stream, so when we apply resolution
+/// to AST, we can be more confident that we are reading resolution data
+/// that is expected to the AST node to which resolution is applied.
+///
+/// This might help us to track if we have a bug and think that some resolution
+/// data can be applied (because its signature is the same), when actually
+/// AST changed in ways that should make resolution incompatible (and so
+/// the resolution signature should have been different).
+bool enableDebugResolutionMarkers = false;
+
 class AstBinaryFlags {
   static final Map<Type, int> _typeBits = {};
 
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart b/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
index 0c19a9e..cf220f2 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
@@ -2,6 +2,324 @@
 // 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.
 
+/// When debugging, these tags are written in resolution information to
+/// mark positions where we expect resolution for specific kinds of nodes.
+/// This might help us to be more confident that we are reading resolution
+/// data that corresponds to AST, and find places where they start
+/// diverging.
+enum MarkerTag {
+  AnnotatedNode_metadata,
+  AnnotatedNode_end,
+  Annotation_name,
+  Annotation_constructorName,
+  Annotation_arguments,
+  Annotation_element,
+  ArgumentList_arguments,
+  ArgumentList_end,
+  AsExpression_expression,
+  AsExpression_type,
+  AsExpression_expression2,
+  AsExpression_end,
+  Expression_staticType,
+  AssertInitializer_condition,
+  AssertInitializer_message,
+  AssertInitializer_end,
+  AssignmentExpression_leftHandSide,
+  AssignmentExpression_rightHandSide,
+  AssignmentExpression_staticElement,
+  AssignmentExpression_readElement,
+  AssignmentExpression_readType,
+  AssignmentExpression_writeElement,
+  AssignmentExpression_writeType,
+  AssignmentExpression_expression,
+  AssignmentExpression_end,
+  BinaryExpression_leftOperand,
+  BinaryExpression_rightOperand,
+  BinaryExpression_staticElement,
+  BinaryExpression_expression,
+  BinaryExpression_end,
+  CascadeExpression_target,
+  CascadeExpression_cascadeSections,
+  CascadeExpression_end,
+  ClassDeclaration_typeParameters,
+  ClassDeclaration_extendsClause,
+  ClassDeclaration_withClause,
+  ClassDeclaration_implementsClause,
+  ClassDeclaration_nativeClause,
+  ClassDeclaration_namedCompilationUnitMember,
+  ClassDeclaration_end,
+  ClassMember_declaration,
+  ClassMember_end,
+  ClassTypeAlias_typeParameters,
+  ClassTypeAlias_superclass,
+  ClassTypeAlias_withClause,
+  ClassTypeAlias_implementsClause,
+  ClassTypeAlias_typeAlias,
+  ClassTypeAlias_end,
+  ConditionalExpression_condition,
+  ConditionalExpression_thenExpression,
+  ConditionalExpression_elseExpression,
+  Configuration_name,
+  Configuration_value,
+  Configuration_uri,
+  Configuration_end,
+  ConstructorDeclaration_returnType,
+  ConstructorDeclaration_parameters,
+  ConstructorDeclaration_initializers,
+  ConstructorDeclaration_redirectedConstructor,
+  ConstructorDeclaration_classMember,
+  ConstructorDeclaration_end,
+  ConstructorFieldInitializer_fieldName,
+  ConstructorFieldInitializer_expression,
+  ConstructorFieldInitializer_end,
+  ConstructorName_type,
+  ConstructorName_name,
+  ConstructorName_staticElement,
+  ConstructorName_end,
+  DeclaredIdentifier_type,
+  DeclaredIdentifier_identifier,
+  DeclaredIdentifier_declaration,
+  DeclaredIdentifier_end,
+  DefaultFormalParameter_parameter,
+  DefaultFormalParameter_defaultValue,
+  DefaultFormalParameter_end,
+  EnumConstantDeclaration_name,
+  EnumConstantDeclaration_declaration,
+  EnumConstantDeclaration_end,
+  EnumDeclaration_constants,
+  EnumDeclaration_namedCompilationUnitMember,
+  EnumDeclaration_end,
+  ExportDirective_namespaceDirective,
+  ExportDirective_exportedLibrary,
+  ExportDirective_end,
+  ExtendsClause_superclass,
+  ExtendsClause_end,
+  ExtensionDeclaration_typeParameters,
+  ExtensionDeclaration_extendedType,
+  ExtensionDeclaration_compilationUnitMember,
+  ExtensionDeclaration_end,
+  ExtensionOverride_extensionName,
+  ExtensionOverride_typeArguments,
+  ExtensionOverride_argumentList,
+  ExtensionOverride_extendedType,
+  ExtensionOverride_end,
+  FieldDeclaration_fields,
+  FieldDeclaration_classMember,
+  FieldDeclaration_end,
+  FieldFormalParameter_typeParameters,
+  FieldFormalParameter_type,
+  FieldFormalParameter_parameters,
+  FieldFormalParameter_normalFormalParameter,
+  FieldFormalParameter_end,
+  ForEachParts_iterable,
+  ForEachParts_forLoopParts,
+  ForEachParts_end,
+  ForEachPartsWithDeclaration_loopVariable,
+  ForEachPartsWithDeclaration_forEachParts,
+  ForEachPartsWithDeclaration_end,
+  ForElement_body,
+  ForElement_forMixin,
+  ForElement_end,
+  FormalParameter_type,
+  ForMixin_forLoopParts,
+  ForParts_condition,
+  ForParts_updaters,
+  ForParts_forLoopParts,
+  ForParts_end,
+  FormalParameterList_parameters,
+  FormalParameterList_end,
+  ForPartsWithDeclarations_variables,
+  ForPartsWithDeclarations_forParts,
+  ForPartsWithDeclarations_end,
+  FunctionDeclaration_functionExpression,
+  FunctionDeclaration_returnType,
+  FunctionDeclaration_namedCompilationUnitMember,
+  FunctionDeclaration_returnTypeType,
+  FunctionDeclaration_end,
+  FunctionExpression_typeParameters,
+  FunctionExpression_parameters,
+  FunctionExpression_end,
+  FunctionExpressionInvocation_function,
+  FunctionExpressionInvocation_invocationExpression,
+  FunctionExpressionInvocation_end,
+  FunctionTypeAlias_typeParameters,
+  FunctionTypeAlias_returnType,
+  FunctionTypeAlias_parameters,
+  FunctionTypeAlias_typeAlias,
+  FunctionTypeAlias_returnTypeType,
+  FunctionTypeAlias_flags,
+  FunctionTypeAlias_end,
+  FunctionTypedFormalParameter_typeParameters,
+  FunctionTypedFormalParameter_returnType,
+  FunctionTypedFormalParameter_parameters,
+  FunctionTypedFormalParameter_normalFormalParameter,
+  FunctionTypedFormalParameter_end,
+  GenericFunctionType_typeParameters,
+  GenericFunctionType_returnType,
+  GenericFunctionType_parameters,
+  GenericFunctionType_type,
+  GenericFunctionType_end,
+  GenericTypeAlias_typeParameters,
+  GenericTypeAlias_type,
+  GenericTypeAlias_typeAlias,
+  GenericTypeAlias_flags,
+  GenericTypeAlias_end,
+  IfElement_condition,
+  IfElement_thenElement,
+  IfElement_elseElement,
+  IfElement_end,
+  ImplementsClause_interfaces,
+  ImplementsClause_end,
+  ImportDirective_namespaceDirective,
+  ImportDirective_importedLibrary,
+  ImportDirective_end,
+  IndexExpression_target,
+  IndexExpression_index,
+  IndexExpression_staticElement,
+  IndexExpression_expression,
+  IndexExpression_end,
+  InstanceCreationExpression_constructorName,
+  InstanceCreationExpression_argumentList,
+  InstanceCreationExpression_expression,
+  InstanceCreationExpression_end,
+  IsExpression_expression,
+  IsExpression_type,
+  IsExpression_expression2,
+  IsExpression_end,
+  InvocationExpression_typeArguments,
+  InvocationExpression_argumentList,
+  InvocationExpression_expression,
+  InvocationExpression_end,
+  ListLiteral_typeArguments,
+  ListLiteral_elements,
+  ListLiteral_expression,
+  ListLiteral_end,
+  MapLiteralEntry_key,
+  MapLiteralEntry_value,
+  MethodDeclaration_typeParameters,
+  MethodDeclaration_returnType,
+  MethodDeclaration_parameters,
+  MethodDeclaration_classMember,
+  MethodDeclaration_returnTypeType,
+  MethodDeclaration_inferenceError,
+  MethodDeclaration_flags,
+  MethodDeclaration_end,
+  MethodInvocation_target,
+  MethodInvocation_methodName,
+  MethodInvocation_invocationExpression,
+  MethodInvocation_end,
+  MixinDeclaration_typeParameters,
+  MixinDeclaration_onClause,
+  MixinDeclaration_implementsClause,
+  MixinDeclaration_namedCompilationUnitMember,
+  MixinDeclaration_end,
+  NamedExpression_expression,
+  NamedExpression_end,
+  NamespaceDirective_combinators,
+  NamespaceDirective_configurations,
+  NamespaceDirective_uriBasedDirective,
+  NamespaceDirective_end,
+  NativeClause_name,
+  NativeClause_end,
+  NormalFormalParameter_metadata,
+  NormalFormalParameter_formalParameter,
+  NormalFormalParameter_end,
+  OnClause_superclassConstraints,
+  OnClause_end,
+  ParenthesizedExpression_expression,
+  ParenthesizedExpression_expression2,
+  ParenthesizedExpression_end,
+  PartOfDirective_libraryName,
+  PartOfDirective_uri,
+  PartOfDirective_directive,
+  PartOfDirective_end,
+  PostfixExpression_operand,
+  PostfixExpression_staticElement,
+  PostfixExpression_readElement,
+  PostfixExpression_readType,
+  PostfixExpression_writeElement,
+  PostfixExpression_writeType,
+  PostfixExpression_expression,
+  PostfixExpression_end,
+  PrefixedIdentifier_prefix,
+  PrefixedIdentifier_identifier,
+  PrefixedIdentifier_expression,
+  PrefixedIdentifier_end,
+  PrefixExpression_operand,
+  PrefixExpression_staticElement,
+  PrefixExpression_readElement,
+  PrefixExpression_readType,
+  PrefixExpression_writeElement,
+  PrefixExpression_writeType,
+  PrefixExpression_expression,
+  PrefixExpression_end,
+  PropertyAccess_target,
+  PropertyAccess_propertyName,
+  PropertyAccess_expression,
+  PropertyAccess_end,
+  RedirectingConstructorInvocation_constructorName,
+  RedirectingConstructorInvocation_argumentList,
+  RedirectingConstructorInvocation_staticElement,
+  RedirectingConstructorInvocation_end,
+  SetOrMapLiteral_flags,
+  SetOrMapLiteral_typeArguments,
+  SetOrMapLiteral_elements,
+  SetOrMapLiteral_expression,
+  SetOrMapLiteral_end,
+  SimpleFormalParameter_type,
+  SimpleFormalParameter_normalFormalParameter,
+  SimpleFormalParameter_flags,
+  SimpleFormalParameter_end,
+  SimpleIdentifier_staticElement,
+  SimpleIdentifier_expression,
+  SimpleIdentifier_end,
+  SpreadElement_expression,
+  SpreadElement_end,
+  StringInterpolation_elements,
+  StringInterpolation_end,
+  SuperConstructorInvocation_constructorName,
+  SuperConstructorInvocation_argumentList,
+  SuperConstructorInvocation_staticElement,
+  SuperConstructorInvocation_end,
+  SuperExpression_expression,
+  SuperExpression_end,
+  ThisExpression_expression,
+  ThisExpression_end,
+  ThrowExpression_expression,
+  ThrowExpression_expression2,
+  ThrowExpression_end,
+  TopLevelVariableDeclaration_variables,
+  TopLevelVariableDeclaration_compilationUnitMember,
+  TopLevelVariableDeclaration_end,
+  TypeArgumentList_arguments,
+  TypeArgumentList_end,
+  TypeName_name,
+  TypeName_typeArguments,
+  TypeName_type,
+  TypeName_end,
+  TypeParameter_bound,
+  TypeParameter_declaration,
+  TypeParameter_variance,
+  TypeParameter_defaultType,
+  TypeParameter_end,
+  TypeParameterList_typeParameters,
+  TypeParameterList_end,
+  UriBasedDirective_uri,
+  UriBasedDirective_directive,
+  UriBasedDirective_end,
+  VariableDeclaration_type,
+  VariableDeclaration_inferenceError,
+  VariableDeclaration_inheritsCovariant,
+  VariableDeclaration_initializer,
+  VariableDeclaration_end,
+  VariableDeclarationList_type,
+  VariableDeclarationList_variables,
+  VariableDeclarationList_annotatedNode,
+  VariableDeclarationList_end,
+  WithClause_mixinTypes,
+  WithClause_end,
+}
+
 /// A `MethodInvocation` in unresolved AST might be rewritten later as
 /// another kinds of AST node. We store this rewrite with resolution data.
 class MethodInvocationRewriteTag {
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index 06f82b6..6f7f8a9 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -34,9 +34,7 @@
   /// for [_classMemberIndexItems]?
   final List<_UnitMemberIndexItem> unitMemberIndexItems = [];
   final List<_ClassMemberIndexItem> _classMemberIndexItems = [];
-  bool _isConstField = false;
-  bool _isFinalField = false;
-  bool _isConstTopLevelVariable = false;
+  bool _shouldStoreVariableInitializers = false;
   bool _hasConstConstructor = false;
   int _nextUnnamedExtensionId = 0;
 
@@ -63,9 +61,12 @@
   void visitAnnotation(Annotation node) {
     _writeByte(Tag.Annotation);
 
+    _writeMarker(MarkerTag.Annotation_name);
     _writeOptionalNode(node.name);
+    _writeMarker(MarkerTag.Annotation_constructorName);
     _writeOptionalNode(node.constructorName);
 
+    _writeMarker(MarkerTag.Annotation_arguments);
     var arguments = node.arguments;
     if (arguments != null) {
       if (!arguments.arguments.every(_isSerializableExpression)) {
@@ -75,6 +76,7 @@
     _writeOptionalNode(arguments);
 
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.Annotation_element);
       _resolutionSink.writeElement(node.element);
     }
   }
@@ -82,29 +84,44 @@
   @override
   void visitArgumentList(ArgumentList node) {
     _writeByte(Tag.ArgumentList);
+    _writeMarker(MarkerTag.ArgumentList_arguments);
     _writeNodeList(node.arguments);
+    _writeMarker(MarkerTag.ArgumentList_end);
   }
 
   @override
   void visitAsExpression(AsExpression node) {
     _writeByte(Tag.AsExpression);
+
+    _writeMarker(MarkerTag.AsExpression_expression);
     _writeNode(node.expression);
+
+    _writeMarker(MarkerTag.AsExpression_type);
     _writeNode(node.type);
+
+    _writeMarker(MarkerTag.AsExpression_expression2);
     _storeExpression(node);
+
+    _writeMarker(MarkerTag.AsExpression_end);
   }
 
   @override
   void visitAssertInitializer(AssertInitializer node) {
     _writeByte(Tag.AssertInitializer);
+    _writeMarker(MarkerTag.AssertInitializer_condition);
     _writeNode(node.condition);
+    _writeMarker(MarkerTag.AssertInitializer_message);
     _writeOptionalNode(node.message);
+    _writeMarker(MarkerTag.AssertInitializer_end);
   }
 
   @override
   void visitAssignmentExpression(AssignmentExpression node) {
     _writeByte(Tag.AssignmentExpression);
 
+    _writeMarker(MarkerTag.AssignmentExpression_leftHandSide);
     _writeNode(node.leftHandSide);
+    _writeMarker(MarkerTag.AssignmentExpression_rightHandSide);
     _writeNode(node.rightHandSide);
 
     var operatorToken = node.operator.type;
@@ -112,20 +129,29 @@
     _writeByte(binaryToken.index);
 
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.AssignmentExpression_staticElement);
       _resolutionSink.writeElement(node.staticElement);
+      _writeMarker(MarkerTag.AssignmentExpression_readElement);
       _resolutionSink.writeElement(node.readElement);
+      _writeMarker(MarkerTag.AssignmentExpression_readType);
       _resolutionSink.writeType(node.readType);
+      _writeMarker(MarkerTag.AssignmentExpression_writeElement);
       _resolutionSink.writeElement(node.writeElement);
+      _writeMarker(MarkerTag.AssignmentExpression_writeType);
       _resolutionSink.writeType(node.writeType);
     }
+    _writeMarker(MarkerTag.AssignmentExpression_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.AssignmentExpression_end);
   }
 
   @override
   void visitBinaryExpression(BinaryExpression node) {
     _writeByte(Tag.BinaryExpression);
 
+    _writeMarker(MarkerTag.BinaryExpression_leftOperand);
     _writeNode(node.leftOperand);
+    _writeMarker(MarkerTag.BinaryExpression_rightOperand);
     _writeNode(node.rightOperand);
 
     var operatorToken = node.operator.type;
@@ -133,9 +159,12 @@
     _writeByte(binaryToken.index);
 
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.BinaryExpression_staticElement);
       _resolutionSink.writeElement(node.staticElement);
-      _resolutionSink.writeType(node.staticType);
     }
+    _writeMarker(MarkerTag.BinaryExpression_expression);
+    _storeExpression(node);
+    _writeMarker(MarkerTag.BinaryExpression_end);
   }
 
   @override
@@ -143,15 +172,18 @@
     _writeByte(Tag.BooleanLiteral);
     _writeByte(node.value ? 1 : 0);
     if (_shouldWriteResolution) {
-      _resolutionSink.writeType(node.staticType);
+      _storeExpression(node);
     }
   }
 
   @override
   void visitCascadeExpression(CascadeExpression node) {
     _writeByte(Tag.CascadeExpression);
+    _writeMarker(MarkerTag.CascadeExpression_target);
     _writeNode(node.target);
+    _writeMarker(MarkerTag.CascadeExpression_cascadeSections);
     _writeNodeList(node.cascadeSections);
+    _writeMarker(MarkerTag.CascadeExpression_end);
   }
 
   @override
@@ -184,12 +216,19 @@
 
     _pushScopeTypeParameters(node.typeParameters);
 
+    _writeMarker(MarkerTag.ClassDeclaration_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.ClassDeclaration_extendsClause);
     _writeOptionalNode(node.extendsClause);
+    _writeMarker(MarkerTag.ClassDeclaration_withClause);
     _writeOptionalNode(node.withClause);
+    _writeMarker(MarkerTag.ClassDeclaration_implementsClause);
     _writeOptionalNode(node.implementsClause);
+    _writeMarker(MarkerTag.ClassDeclaration_nativeClause);
     _writeOptionalNode(node.nativeClause);
+    _writeMarker(MarkerTag.ClassDeclaration_namedCompilationUnitMember);
     _storeNamedCompilationUnitMember(node);
+    _writeMarker(MarkerTag.ClassDeclaration_end);
     _writeUInt30(resolutionIndex);
 
     _classMemberIndexItems.clear();
@@ -238,11 +277,17 @@
     _writeInformativeUint30(node.offset);
     _writeInformativeUint30(node.length);
     _pushScopeTypeParameters(node.typeParameters);
+    _writeMarker(MarkerTag.ClassTypeAlias_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.ClassTypeAlias_superclass);
     _writeNode(node.superclass);
+    _writeMarker(MarkerTag.ClassTypeAlias_withClause);
     _writeNode(node.withClause);
+    _writeMarker(MarkerTag.ClassTypeAlias_implementsClause);
     _writeOptionalNode(node.implementsClause);
+    _writeMarker(MarkerTag.ClassTypeAlias_typeAlias);
     _storeTypeAlias(node);
+    _writeMarker(MarkerTag.ClassTypeAlias_end);
     _writeDocumentationCommentString(node.documentationComment);
     _writeUInt30(resolutionIndex);
     if (_shouldWriteResolution) {
@@ -266,8 +311,11 @@
   @override
   void visitConditionalExpression(ConditionalExpression node) {
     _writeByte(Tag.ConditionalExpression);
+    _writeMarker(MarkerTag.ConditionalExpression_condition);
     _writeNode(node.condition);
+    _writeMarker(MarkerTag.ConditionalExpression_thenExpression);
     _writeNode(node.thenExpression);
+    _writeMarker(MarkerTag.ConditionalExpression_elseExpression);
     _writeNode(node.elseExpression);
     _storeExpression(node);
   }
@@ -282,9 +330,13 @@
       ),
     );
 
+    _writeMarker(MarkerTag.Configuration_name);
     _writeNode(node.name);
+    _writeMarker(MarkerTag.Configuration_value);
     _writeOptionalNode(node.value);
+    _writeMarker(MarkerTag.Configuration_uri);
     _writeNode(node.uri);
+    _writeMarker(MarkerTag.Configuration_end);
   }
 
   @override
@@ -316,11 +368,13 @@
     _writeDocumentationCommentString(node.documentationComment);
 
     var resolutionIndex = _getNextResolutionIndex();
+    _writeMarker(MarkerTag.ConstructorDeclaration_returnType);
     _writeNode(node.returnType);
     if (node.period != null) {
       _writeInformativeUint30(node.period.offset);
       _writeDeclarationName(node.name);
     }
+    _writeMarker(MarkerTag.ConstructorDeclaration_parameters);
     _writeNode(node.parameters);
 
     if (_shouldWriteResolution) {
@@ -332,6 +386,7 @@
 
     // TODO(scheglov) Not nice, we skip both resolution and AST.
     // But eventually we want to store full AST, and partial resolution.
+    _writeMarker(MarkerTag.ConstructorDeclaration_initializers);
     if (node.constKeyword != null) {
       _writeNodeList(node.initializers);
     } else {
@@ -342,8 +397,11 @@
       _resolutionSink.localElements.popScope();
     }
 
+    _writeMarker(MarkerTag.ConstructorDeclaration_redirectedConstructor);
     _writeOptionalNode(node.redirectedConstructor);
+    _writeMarker(MarkerTag.ConstructorDeclaration_classMember);
     _storeClassMember(node);
+    _writeMarker(MarkerTag.ConstructorDeclaration_end);
     _writeUInt30(resolutionIndex);
   }
 
@@ -357,9 +415,11 @@
       ),
     );
 
+    _writeMarker(MarkerTag.ConstructorFieldInitializer_fieldName);
     _writeNode(node.fieldName);
+    _writeMarker(MarkerTag.ConstructorFieldInitializer_expression);
     _writeNode(node.expression);
-    _storeConstructorInitializer(node);
+    _writeMarker(MarkerTag.ConstructorFieldInitializer_end);
   }
 
   @override
@@ -374,12 +434,17 @@
       _resolutionSink.writeByte(node.name != null ? 1 : 0);
     }
 
+    _writeMarker(MarkerTag.ConstructorName_type);
     _writeNode(node.type);
+    _writeMarker(MarkerTag.ConstructorName_name);
     _writeOptionalNode(node.name);
 
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.ConstructorName_staticElement);
       _resolutionSink.writeElement(node.staticElement);
     }
+
+    _writeMarker(MarkerTag.ConstructorName_end);
   }
 
   @override
@@ -392,9 +457,13 @@
         isVar: node.keyword?.keyword == Keyword.VAR,
       ),
     );
+    _writeMarker(MarkerTag.DeclaredIdentifier_type);
     _writeOptionalNode(node.type);
+    _writeMarker(MarkerTag.DeclaredIdentifier_identifier);
     _writeDeclarationName(node.identifier);
+    _writeMarker(MarkerTag.DeclaredIdentifier_declaration);
     _storeDeclaration(node);
+    _writeMarker(MarkerTag.DeclaredIdentifier_end);
   }
 
   @override
@@ -412,13 +481,16 @@
     _writeInformativeUint30(node.offset);
     _writeInformativeUint30(node.length);
 
+    _writeMarker(MarkerTag.DefaultFormalParameter_parameter);
     _writeNode(node.parameter);
 
     var defaultValue = node.defaultValue;
     if (!_isSerializableExpression(defaultValue)) {
       defaultValue = null;
     }
+    _writeMarker(MarkerTag.DefaultFormalParameter_defaultValue);
     _writeOptionalNode(defaultValue);
+    _writeMarker(MarkerTag.DefaultFormalParameter_end);
   }
 
   @override
@@ -441,8 +513,11 @@
     _writeInformativeUint30(node.length);
     _writeDocumentationCommentString(node.documentationComment);
 
+    _writeMarker(MarkerTag.EnumConstantDeclaration_name);
     _writeDeclarationName(node.name);
+    _writeMarker(MarkerTag.EnumConstantDeclaration_declaration);
     _storeDeclaration(node);
+    _writeMarker(MarkerTag.EnumConstantDeclaration_end);
   }
 
   @override
@@ -462,8 +537,11 @@
     _writeInformativeUint30(node.length);
     _writeDocumentationCommentString(node.documentationComment);
 
+    _writeMarker(MarkerTag.EnumDeclaration_constants);
     _writeNodeList(node.constants);
+    _writeMarker(MarkerTag.EnumDeclaration_namedCompilationUnitMember);
     _storeNamedCompilationUnitMember(node);
+    _writeMarker(MarkerTag.EnumDeclaration_end);
     _writeUInt30(resolutionIndex);
   }
 
@@ -472,20 +550,26 @@
     var resolutionIndex = _getNextResolutionIndex();
 
     _writeByte(Tag.ExportDirective);
+    _writeMarker(MarkerTag.ExportDirective_namespaceDirective);
     _storeNamespaceDirective(node);
     _writeUInt30(resolutionIndex);
 
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.ExportDirective_exportedLibrary);
       _resolutionSink.writeElement(
         (node.element as ExportElementImpl).exportedLibrary,
       );
     }
+
+    _writeMarker(MarkerTag.ExportDirective_end);
   }
 
   @override
   void visitExtendsClause(ExtendsClause node) {
     _writeByte(Tag.ExtendsClause);
+    _writeMarker(MarkerTag.ExtendsClause_superclass);
     _writeNode(node.superclass);
+    _writeMarker(MarkerTag.ExtendsClause_end);
   }
 
   @override
@@ -500,10 +584,14 @@
     _writeDocumentationCommentString(node.documentationComment);
 
     _pushScopeTypeParameters(node.typeParameters);
+    _writeMarker(MarkerTag.ExtensionDeclaration_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.ExtensionDeclaration_extendedType);
     _writeNode(node.extendedType);
     _writeOptionalDeclarationName(node.name);
+    _writeMarker(MarkerTag.ExtensionDeclaration_compilationUnitMember);
     _storeCompilationUnitMember(node);
+    _writeMarker(MarkerTag.ExtensionDeclaration_end);
     _writeUInt30(resolutionIndex);
 
     _classMemberIndexItems.clear();
@@ -539,10 +627,15 @@
       _resolutionSink.writeByte(MethodInvocationRewriteTag.extensionOverride);
     }
 
+    _writeMarker(MarkerTag.ExtensionOverride_extensionName);
     _writeNode(node.extensionName);
+    _writeMarker(MarkerTag.ExtensionOverride_typeArguments);
     _writeOptionalNode(node.typeArguments);
+    _writeMarker(MarkerTag.ExtensionOverride_argumentList);
     _writeNode(node.argumentList);
+    _writeMarker(MarkerTag.ExtensionOverride_extendedType);
     _resolutionSink.writeType(node.extendedType);
+    _writeMarker(MarkerTag.ExtensionOverride_end);
     // TODO(scheglov) typeArgumentTypes?
   }
 
@@ -571,16 +664,18 @@
 
     var resolutionIndex = _getNextResolutionIndex();
 
-    _isConstField = node.fields.isConst;
-    _isFinalField = node.fields.isFinal;
+    _shouldStoreVariableInitializers = node.fields.isConst ||
+        _hasConstConstructor && node.fields.isFinal && !node.isStatic;
     try {
+      _writeMarker(MarkerTag.FieldDeclaration_fields);
       _writeNode(node.fields);
     } finally {
-      _isConstField = false;
-      _isFinalField = false;
+      _shouldStoreVariableInitializers = false;
     }
 
+    _writeMarker(MarkerTag.FieldDeclaration_classMember);
     _storeClassMember(node);
+    _writeMarker(MarkerTag.FieldDeclaration_end);
 
     _writeUInt30(resolutionIndex);
   }
@@ -590,14 +685,19 @@
     _writeByte(Tag.FieldFormalParameter);
 
     _pushScopeTypeParameters(node.typeParameters);
+    _writeMarker(MarkerTag.FieldFormalParameter_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.FieldFormalParameter_type);
     _writeOptionalNode(node.type);
+    _writeMarker(MarkerTag.FieldFormalParameter_parameters);
     _writeOptionalNode(node.parameters);
+    _writeMarker(MarkerTag.FieldFormalParameter_normalFormalParameter);
     _storeNormalFormalParameter(
       node,
       node.keyword,
       hasQuestion: node.question != null,
     );
+    _writeMarker(MarkerTag.FieldFormalParameter_end);
 
     if (_shouldWriteResolution) {
       _resolutionSink.localElements.popScope();
@@ -607,15 +707,21 @@
   @override
   void visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
     _writeByte(Tag.ForEachPartsWithDeclaration);
+    _writeMarker(MarkerTag.ForEachPartsWithDeclaration_loopVariable);
     _writeNode(node.loopVariable);
+    _writeMarker(MarkerTag.ForEachPartsWithDeclaration_forEachParts);
     _storeForEachParts(node);
+    _writeMarker(MarkerTag.ForEachPartsWithDeclaration_end);
   }
 
   @override
   void visitForElement(ForElement node) {
     _writeByte(Tag.ForElement);
+    _writeMarker(MarkerTag.ForElement_body);
     _writeNode(node.body);
+    _writeMarker(MarkerTag.ForElement_forMixin);
     _storeForMixin(node as ForElementImpl);
+    _writeMarker(MarkerTag.ForElement_end);
   }
 
   @override
@@ -630,14 +736,19 @@
       ),
     );
 
+    _writeMarker(MarkerTag.FormalParameterList_parameters);
     _writeNodeList(node.parameters);
+    _writeMarker(MarkerTag.FormalParameterList_end);
   }
 
   @override
   void visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
     _writeByte(Tag.ForPartsWithDeclarations);
+    _writeMarker(MarkerTag.ForPartsWithDeclarations_variables);
     _writeNode(node.variables);
+    _writeMarker(MarkerTag.ForPartsWithDeclarations_forParts);
     _storeForParts(node);
+    _writeMarker(MarkerTag.ForPartsWithDeclarations_end);
   }
 
   @override
@@ -675,15 +786,21 @@
 
     _pushScopeTypeParameters(node.functionExpression.typeParameters);
 
+    _writeMarker(MarkerTag.FunctionDeclaration_functionExpression);
     _writeNode(node.functionExpression);
+    _writeMarker(MarkerTag.FunctionDeclaration_returnType);
     _writeOptionalNode(node.returnType);
+    _writeMarker(MarkerTag.FunctionDeclaration_namedCompilationUnitMember);
     _storeNamedCompilationUnitMember(node);
 
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.FunctionDeclaration_returnTypeType);
       _writeActualReturnType(node.declaredElement.returnType);
       _resolutionSink.localElements.popScope();
     }
 
+    _writeMarker(MarkerTag.FunctionDeclaration_end);
+
     _writeUInt30(resolutionIndex);
   }
 
@@ -699,8 +816,11 @@
       ),
     );
 
+    _writeMarker(MarkerTag.FunctionExpression_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.FunctionExpression_parameters);
     _writeOptionalNode(node.parameters);
+    _writeMarker(MarkerTag.FunctionExpression_end);
   }
 
   @override
@@ -712,8 +832,11 @@
           .writeByte(MethodInvocationRewriteTag.functionExpressionInvocation);
     }
 
+    _writeMarker(MarkerTag.FunctionExpressionInvocation_function);
     _writeNode(node.function);
+    _writeMarker(MarkerTag.FunctionExpressionInvocation_invocationExpression);
     _storeInvocationExpression(node);
+    _writeMarker(MarkerTag.FunctionExpressionInvocation_end);
   }
 
   @override
@@ -737,22 +860,30 @@
 
     _pushScopeTypeParameters(node.typeParameters);
 
+    _writeMarker(MarkerTag.FunctionTypeAlias_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.FunctionTypeAlias_returnType);
     _writeOptionalNode(node.returnType);
+    _writeMarker(MarkerTag.FunctionTypeAlias_parameters);
     _writeNode(node.parameters);
 
+    _writeMarker(MarkerTag.FunctionTypeAlias_typeAlias);
     _storeTypeAlias(node);
 
     if (_shouldWriteResolution) {
       var element = node.declaredElement as FunctionTypeAliasElementImpl;
+      _writeMarker(MarkerTag.FunctionTypeAlias_returnTypeType);
       _writeActualReturnType(element.function.returnType);
       // TODO(scheglov) pack into one byte
+      _writeMarker(MarkerTag.FunctionTypeAlias_flags);
       _resolutionSink.writeByte(element.isSimplyBounded ? 1 : 0);
       _resolutionSink.writeByte(element.hasSelfReference ? 1 : 0);
 
       _resolutionSink.localElements.popScope();
     }
 
+    _writeMarker(MarkerTag.FunctionTypeAlias_end);
+
     _writeUInt30(resolutionIndex);
   }
 
@@ -761,10 +892,15 @@
     _writeByte(Tag.FunctionTypedFormalParameter);
 
     _pushScopeTypeParameters(node.typeParameters);
+    _writeMarker(MarkerTag.FunctionTypedFormalParameter_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.FunctionTypedFormalParameter_returnType);
     _writeOptionalNode(node.returnType);
+    _writeMarker(MarkerTag.FunctionTypedFormalParameter_parameters);
     _writeNode(node.parameters);
+    _writeMarker(MarkerTag.FunctionTypedFormalParameter_normalFormalParameter);
     _storeNormalFormalParameter(node, null);
+    _writeMarker(MarkerTag.FunctionTypedFormalParameter_end);
 
     if (_shouldWriteResolution) {
       _resolutionSink.localElements.popScope();
@@ -783,14 +919,20 @@
 
     _pushScopeTypeParameters(node.typeParameters);
 
+    _writeMarker(MarkerTag.GenericFunctionType_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.GenericFunctionType_returnType);
     _writeOptionalNode(node.returnType);
+    _writeMarker(MarkerTag.GenericFunctionType_parameters);
     _writeNode(node.parameters);
 
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.GenericFunctionType_type);
       _resolutionSink.writeType(node.type);
       _resolutionSink.localElements.popScope();
     }
+
+    _writeMarker(MarkerTag.GenericFunctionType_end);
   }
 
   @override
@@ -813,18 +955,24 @@
 
     _pushScopeTypeParameters(node.typeParameters);
 
+    _writeMarker(MarkerTag.GenericTypeAlias_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.GenericTypeAlias_type);
     _writeOptionalNode(node.type);
+    _writeMarker(MarkerTag.GenericTypeAlias_typeAlias);
     _storeTypeAlias(node);
 
     if (_shouldWriteResolution) {
       var element = node.declaredElement as TypeAliasElementImpl;
       // TODO(scheglov) pack into one byte
+      _writeMarker(MarkerTag.GenericTypeAlias_flags);
       _resolutionSink.writeByte(element.isSimplyBounded ? 1 : 0);
       _resolutionSink.writeByte(element.hasSelfReference ? 1 : 0);
       _resolutionSink.localElements.popScope();
     }
 
+    _writeMarker(MarkerTag.GenericTypeAlias_end);
+
     _writeUInt30(resolutionIndex);
   }
 
@@ -838,15 +986,21 @@
   @override
   void visitIfElement(IfElement node) {
     _writeByte(Tag.IfElement);
+    _writeMarker(MarkerTag.IfElement_condition);
     _writeNode(node.condition);
+    _writeMarker(MarkerTag.IfElement_thenElement);
     _writeNode(node.thenElement);
+    _writeMarker(MarkerTag.IfElement_elseElement);
     _writeOptionalNode(node.elseElement);
+    _writeMarker(MarkerTag.IfElement_end);
   }
 
   @override
   void visitImplementsClause(ImplementsClause node) {
     _writeByte(Tag.ImplementsClause);
+    _writeMarker(MarkerTag.ImplementsClause_interfaces);
     _writeNodeList(node.interfaces);
+    _writeMarker(MarkerTag.ImplementsClause_end);
   }
 
   @override
@@ -868,13 +1022,17 @@
       _writeInformativeUint30(prefix.offset);
     }
 
+    _writeMarker(MarkerTag.ImportDirective_namespaceDirective);
     _storeNamespaceDirective(node);
     _writeUInt30(resolutionIndex);
 
     if (_shouldWriteResolution) {
       var element = node.element as ImportElementImpl;
+      _writeMarker(MarkerTag.ImportDirective_importedLibrary);
       _resolutionSink.writeElement(element.importedLibrary);
     }
+
+    _writeMarker(MarkerTag.ImportDirective_end);
   }
 
   @override
@@ -886,12 +1044,17 @@
         hasQuestion: node.question != null,
       ),
     );
+    _writeMarker(MarkerTag.IndexExpression_target);
     _writeOptionalNode(node.target);
+    _writeMarker(MarkerTag.IndexExpression_index);
     _writeNode(node.index);
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.IndexExpression_staticElement);
       _resolutionSink.writeElement(node.staticElement);
     }
+    _writeMarker(MarkerTag.IndexExpression_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.IndexExpression_end);
   }
 
   @override
@@ -917,9 +1080,13 @@
       ),
     );
 
+    _writeMarker(MarkerTag.InstanceCreationExpression_constructorName);
     _writeNode(node.constructorName);
+    _writeMarker(MarkerTag.InstanceCreationExpression_argumentList);
     _writeNode(node.argumentList);
+    _writeMarker(MarkerTag.InstanceCreationExpression_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.InstanceCreationExpression_end);
   }
 
   @override
@@ -951,10 +1118,8 @@
       }
     }
 
-    if (_shouldWriteResolution) {
-      // TODO(scheglov) Dont write type, AKA separate true `int` and `double`?
-      _resolutionSink.writeType(node.staticType);
-    }
+    // TODO(scheglov) Dont write type, AKA separate true `int` and `double`?
+    _storeExpression(node);
   }
 
   @override
@@ -983,9 +1148,13 @@
         hasNot: node.notOperator != null,
       ),
     );
+    _writeMarker(MarkerTag.IsExpression_expression);
     _writeNode(node.expression);
+    _writeMarker(MarkerTag.IsExpression_type);
     _writeNode(node.type);
+    _writeMarker(MarkerTag.IsExpression_expression2);
     _storeExpression(node);
+    _writeMarker(MarkerTag.IsExpression_end);
   }
 
   @override
@@ -1012,16 +1181,22 @@
       ),
     );
 
+    _writeMarker(MarkerTag.ListLiteral_typeArguments);
     _writeOptionalNode(node.typeArguments);
+    _writeMarker(MarkerTag.ListLiteral_elements);
     _writeNodeList(node.elements);
 
+    _writeMarker(MarkerTag.ListLiteral_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.ListLiteral_end);
   }
 
   @override
   void visitMapLiteralEntry(MapLiteralEntry node) {
     _writeByte(Tag.MapLiteralEntry);
+    _writeMarker(MarkerTag.MapLiteralEntry_key);
     _writeNode(node.key);
+    _writeMarker(MarkerTag.MapLiteralEntry_value);
     _writeNode(node.value);
   }
 
@@ -1066,26 +1241,35 @@
     _pushScopeTypeParameters(node.typeParameters);
 
     _writeDeclarationName(node.name);
+    _writeMarker(MarkerTag.MethodDeclaration_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.MethodDeclaration_returnType);
     _writeOptionalNode(node.returnType);
+    _writeMarker(MarkerTag.MethodDeclaration_parameters);
     _writeOptionalNode(node.parameters);
 
+    _writeMarker(MarkerTag.MethodDeclaration_classMember);
     _storeClassMember(node);
 
     _writeUInt30(resolutionIndex);
 
     if (_shouldWriteResolution) {
       var element = node.declaredElement as ExecutableElementImpl;
+      _writeMarker(MarkerTag.MethodDeclaration_returnTypeType);
       _writeActualReturnType(element.returnType);
+      _writeMarker(MarkerTag.MethodDeclaration_inferenceError);
       _writeTopLevelInferenceError(element);
       // TODO(scheglov) move this flag into ClassElementImpl?
       if (element is MethodElementImpl) {
+        _writeMarker(MarkerTag.MethodDeclaration_flags);
         _resolutionSink.writeByte(
           element.isOperatorEqualWithParameterTypeFromObject ? 1 : 0,
         );
       }
       _resolutionSink.localElements.popScope();
     }
+
+    _writeMarker(MarkerTag.MethodDeclaration_end);
   }
 
   @override
@@ -1102,9 +1286,13 @@
         hasPeriod2: node.operator?.type == TokenType.PERIOD_PERIOD,
       ),
     );
+    _writeMarker(MarkerTag.MethodInvocation_target);
     _writeOptionalNode(node.target);
+    _writeMarker(MarkerTag.MethodInvocation_methodName);
     _writeNode(node.methodName);
+    _writeMarker(MarkerTag.MethodInvocation_invocationExpression);
     _storeInvocationExpression(node);
+    _writeMarker(MarkerTag.MethodInvocation_end);
   }
 
   @override
@@ -1126,10 +1314,15 @@
 
     _pushScopeTypeParameters(node.typeParameters);
 
+    _writeMarker(MarkerTag.MixinDeclaration_typeParameters);
     _writeOptionalNode(node.typeParameters);
+    _writeMarker(MarkerTag.MixinDeclaration_onClause);
     _writeOptionalNode(node.onClause);
+    _writeMarker(MarkerTag.MixinDeclaration_implementsClause);
     _writeOptionalNode(node.implementsClause);
+    _writeMarker(MarkerTag.MixinDeclaration_namedCompilationUnitMember);
     _storeNamedCompilationUnitMember(node);
+    _writeMarker(MarkerTag.MixinDeclaration_end);
     _writeUInt30(resolutionIndex);
 
     _classMemberIndexItems.clear();
@@ -1162,13 +1355,17 @@
     _writeStringReference(nameNode.name);
     _writeInformativeUint30(nameNode.offset);
 
+    _writeMarker(MarkerTag.NamedExpression_expression);
     _writeNode(node.expression);
+    _writeMarker(MarkerTag.NamedExpression_end);
   }
 
   @override
   void visitNativeClause(NativeClause node) {
     _writeByte(Tag.NativeClause);
+    _writeMarker(MarkerTag.NativeClause_name);
     _writeNode(node.name);
+    _writeMarker(MarkerTag.NativeClause_end);
   }
 
   @override
@@ -1179,14 +1376,19 @@
   @override
   void visitOnClause(OnClause node) {
     _writeByte(Tag.OnClause);
+    _writeMarker(MarkerTag.OnClause_superclassConstraints);
     _writeNodeList(node.superclassConstraints);
+    _writeMarker(MarkerTag.OnClause_end);
   }
 
   @override
   void visitParenthesizedExpression(ParenthesizedExpression node) {
     _writeByte(Tag.ParenthesizedExpression);
+    _writeMarker(MarkerTag.ParenthesizedExpression_expression);
     _writeNode(node.expression);
+    _writeMarker(MarkerTag.ParenthesizedExpression_expression2);
     _storeExpression(node);
+    _writeMarker(MarkerTag.ParenthesizedExpression_end);
   }
 
   @override
@@ -1198,15 +1400,20 @@
   @override
   void visitPartOfDirective(PartOfDirective node) {
     _writeByte(Tag.PartOfDirective);
+    _writeMarker(MarkerTag.PartOfDirective_libraryName);
     _writeOptionalNode(node.libraryName);
+    _writeMarker(MarkerTag.PartOfDirective_uri);
     _writeOptionalNode(node.uri);
+    _writeMarker(MarkerTag.PartOfDirective_directive);
     _storeDirective(node);
+    _writeMarker(MarkerTag.PartOfDirective_end);
   }
 
   @override
   void visitPostfixExpression(PostfixExpression node) {
     _writeByte(Tag.PostfixExpression);
 
+    _writeMarker(MarkerTag.PostfixExpression_operand);
     _writeNode(node.operand);
 
     var operatorToken = node.operator.type;
@@ -1214,27 +1421,36 @@
     _writeByte(binaryToken.index);
 
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.PostfixExpression_staticElement);
       _resolutionSink.writeElement(node.staticElement);
       if (operatorToken.isIncrementOperator) {
+        _writeMarker(MarkerTag.PostfixExpression_readElement);
         _resolutionSink.writeElement(node.readElement);
+        _writeMarker(MarkerTag.PostfixExpression_readType);
         _resolutionSink.writeType(node.readType);
+        _writeMarker(MarkerTag.PostfixExpression_writeElement);
         _resolutionSink.writeElement(node.writeElement);
+        _writeMarker(MarkerTag.PostfixExpression_writeType);
         _resolutionSink.writeType(node.writeType);
       }
     }
+    _writeMarker(MarkerTag.PostfixExpression_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.PostfixExpression_end);
   }
 
   @override
   void visitPrefixedIdentifier(PrefixedIdentifier node) {
     _writeByte(Tag.PrefixedIdentifier);
+    _writeMarker(MarkerTag.PrefixedIdentifier_prefix);
     _writeNode(node.prefix);
+    _writeMarker(MarkerTag.PrefixedIdentifier_identifier);
     _writeNode(node.identifier);
 
-    if (_shouldWriteResolution) {
-      // TODO(scheglov) In actual prefixed identifier, the type of the identifier.
-      _resolutionSink.writeType(node.staticType);
-    }
+    // TODO(scheglov) In actual prefixed identifier, the type of the identifier.
+    _writeMarker(MarkerTag.PrefixedIdentifier_expression);
+    _storeExpression(node);
+    _writeMarker(MarkerTag.PrefixedIdentifier_end);
   }
 
   @override
@@ -1245,19 +1461,27 @@
     var binaryToken = TokensWriter.astToBinaryTokenType(operatorToken);
     _writeByte(binaryToken.index);
 
+    _writeMarker(MarkerTag.PrefixExpression_operand);
     _writeNode(node.operand);
 
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.PrefixExpression_staticElement);
       _resolutionSink.writeElement(node.staticElement);
       if (operatorToken.isIncrementOperator) {
+        _writeMarker(MarkerTag.PrefixExpression_readElement);
         _resolutionSink.writeElement(node.readElement);
+        _writeMarker(MarkerTag.PrefixExpression_readType);
         _resolutionSink.writeType(node.readType);
+        _writeMarker(MarkerTag.PrefixExpression_writeElement);
         _resolutionSink.writeElement(node.writeElement);
+        _writeMarker(MarkerTag.PrefixExpression_writeType);
         _resolutionSink.writeType(node.writeType);
       }
     }
 
+    _writeMarker(MarkerTag.PrefixExpression_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.PrefixExpression_end);
   }
 
   @override
@@ -1269,10 +1493,14 @@
         hasPeriod2: node.operator?.type == TokenType.PERIOD_PERIOD,
       ),
     );
+    _writeMarker(MarkerTag.PropertyAccess_target);
     _writeOptionalNode(node.target);
+    _writeMarker(MarkerTag.PropertyAccess_propertyName);
     _writeNode(node.propertyName);
     // TODO(scheglov) Get from the property?
+    _writeMarker(MarkerTag.PropertyAccess_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.PropertyAccess_end);
   }
 
   @override
@@ -1286,12 +1514,15 @@
       ),
     );
 
+    _writeMarker(MarkerTag.RedirectingConstructorInvocation_constructorName);
     _writeOptionalNode(node.constructorName);
+    _writeMarker(MarkerTag.RedirectingConstructorInvocation_argumentList);
     _writeNode(node.argumentList);
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.RedirectingConstructorInvocation_staticElement);
       _resolutionSink.writeElement(node.staticElement);
     }
-    _storeConstructorInitializer(node);
+    _writeMarker(MarkerTag.RedirectingConstructorInvocation_end);
   }
 
   @override
@@ -1307,13 +1538,18 @@
     if (_shouldWriteResolution) {
       var isMapBit = node.isMap ? (1 << 0) : 0;
       var isSetBit = node.isSet ? (1 << 1) : 0;
+      _writeMarker(MarkerTag.SetOrMapLiteral_flags);
       _resolutionSink.writeByte(isMapBit | isSetBit);
     }
 
+    _writeMarker(MarkerTag.SetOrMapLiteral_typeArguments);
     _writeOptionalNode(node.typeArguments);
+    _writeMarker(MarkerTag.SetOrMapLiteral_elements);
     _writeNodeList(node.elements);
 
+    _writeMarker(MarkerTag.SetOrMapLiteral_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.SetOrMapLiteral_end);
   }
 
   @override
@@ -1327,13 +1563,17 @@
   void visitSimpleFormalParameter(SimpleFormalParameter node) {
     _writeByte(Tag.SimpleFormalParameter);
 
+    _writeMarker(MarkerTag.SimpleFormalParameter_type);
     _writeOptionalNode(node.type);
+    _writeMarker(MarkerTag.SimpleFormalParameter_normalFormalParameter);
     _storeNormalFormalParameter(node, node.keyword);
 
     if (_shouldWriteResolution) {
       var element = node.declaredElement as ParameterElementImpl;
+      _writeMarker(MarkerTag.SimpleFormalParameter_flags);
       _resolutionSink.writeByte(element.inheritsCovariant ? 1 : 0);
     }
+    _writeMarker(MarkerTag.SimpleFormalParameter_end);
   }
 
   @override
@@ -1342,10 +1582,13 @@
     _writeStringReference(node.name);
     _writeInformativeUint30(node.offset);
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.SimpleIdentifier_staticElement);
       _resolutionSink.writeElement(node.staticElement);
       // TODO(scheglov) It is inefficient to write many null types.
-      _resolutionSink.writeType(node.staticType);
     }
+    _writeMarker(MarkerTag.SimpleIdentifier_expression);
+    _storeExpression(node);
+    _writeMarker(MarkerTag.SimpleIdentifier_end);
   }
 
   @override
@@ -1364,31 +1607,40 @@
             node.spreadOperator.type == TokenType.PERIOD_PERIOD_PERIOD_QUESTION,
       ),
     );
+    _writeMarker(MarkerTag.SpreadElement_expression);
     _writeNode(node.expression);
+    _writeMarker(MarkerTag.SpreadElement_end);
   }
 
   @override
   void visitStringInterpolation(StringInterpolation node) {
     _writeByte(Tag.StringInterpolation);
+    _writeMarker(MarkerTag.StringInterpolation_elements);
     _writeNodeList(node.elements);
+    _writeMarker(MarkerTag.StringInterpolation_end);
   }
 
   @override
   void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
     _writeByte(Tag.SuperConstructorInvocation);
 
+    _writeMarker(MarkerTag.SuperConstructorInvocation_constructorName);
     _writeOptionalNode(node.constructorName);
+    _writeMarker(MarkerTag.SuperConstructorInvocation_argumentList);
     _writeNode(node.argumentList);
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.SuperConstructorInvocation_staticElement);
       _resolutionSink.writeElement(node.staticElement);
     }
-    _storeConstructorInitializer(node);
+    _writeMarker(MarkerTag.SuperConstructorInvocation_end);
   }
 
   @override
   void visitSuperExpression(SuperExpression node) {
     _writeByte(Tag.SuperExpression);
+    _writeMarker(MarkerTag.SuperExpression_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.SuperExpression_end);
   }
 
   @override
@@ -1406,14 +1658,19 @@
   @override
   void visitThisExpression(ThisExpression node) {
     _writeByte(Tag.ThisExpression);
+    _writeMarker(MarkerTag.ThisExpression_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.ThisExpression_end);
   }
 
   @override
   void visitThrowExpression(ThrowExpression node) {
     _writeByte(Tag.ThrowExpression);
+    _writeMarker(MarkerTag.ThrowExpression_expression);
     _writeNode(node.expression);
+    _writeMarker(MarkerTag.ThrowExpression_expression2);
     _storeExpression(node);
+    _writeMarker(MarkerTag.ThrowExpression_end);
   }
 
   @override
@@ -1440,14 +1697,17 @@
 
     var resolutionIndex = _getNextResolutionIndex();
 
-    _isConstTopLevelVariable = node.variables.isConst;
+    _shouldStoreVariableInitializers = node.variables.isConst;
     try {
+      _writeMarker(MarkerTag.TopLevelVariableDeclaration_variables);
       _writeNode(node.variables);
     } finally {
-      _isConstTopLevelVariable = false;
+      _shouldStoreVariableInitializers = false;
     }
 
+    _writeMarker(MarkerTag.TopLevelVariableDeclaration_compilationUnitMember);
     _storeCompilationUnitMember(node);
+    _writeMarker(MarkerTag.TopLevelVariableDeclaration_end);
 
     _writeUInt30(resolutionIndex);
   }
@@ -1455,7 +1715,9 @@
   @override
   void visitTypeArgumentList(TypeArgumentList node) {
     _writeByte(Tag.TypeArgumentList);
+    _writeMarker(MarkerTag.TypeArgumentList_arguments);
     _writeNodeList(node.arguments);
+    _writeMarker(MarkerTag.TypeArgumentList_end);
   }
 
   @override
@@ -1469,12 +1731,16 @@
       ),
     );
 
+    _writeMarker(MarkerTag.TypeName_name);
     _writeNode(node.name);
+    _writeMarker(MarkerTag.TypeName_typeArguments);
     _writeOptionalNode(node.typeArguments);
 
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.TypeName_type);
       _resolutionSink.writeType(node.type);
     }
+    _writeMarker(MarkerTag.TypeName_end);
   }
 
   @override
@@ -1483,22 +1749,29 @@
     _writeInformativeUint30(node.offset);
     _writeInformativeUint30(node.length);
     _writeDeclarationName(node.name);
+    _writeMarker(MarkerTag.TypeParameter_bound);
     _writeOptionalNode(node.bound);
+    _writeMarker(MarkerTag.TypeParameter_declaration);
     _storeDeclaration(node);
 
     if (_shouldWriteResolution) {
       var element = node.declaredElement as TypeParameterElementImpl;
+      _writeMarker(MarkerTag.TypeParameter_variance);
       _resolutionSink.writeByte(
         _encodeVariance(element),
       );
+      _writeMarker(MarkerTag.TypeParameter_defaultType);
       _resolutionSink.writeType(element.defaultType);
     }
+    _writeMarker(MarkerTag.TypeParameter_end);
   }
 
   @override
   void visitTypeParameterList(TypeParameterList node) {
     _writeByte(Tag.TypeParameterList);
+    _writeMarker(MarkerTag.TypeParameterList_typeParameters);
     _writeNodeList(node.typeParameters);
+    _writeMarker(MarkerTag.TypeParameterList_end);
   }
 
   @override
@@ -1514,23 +1787,26 @@
     if (_shouldWriteResolution) {
       // TODO(scheglov) Enforce not null, remove `?` in `?.type` below.
       var element = node.declaredElement as VariableElementImpl;
+      _writeMarker(MarkerTag.VariableDeclaration_type);
       _writeActualType(element?.type);
+      _writeMarker(MarkerTag.VariableDeclaration_inferenceError);
       _writeTopLevelInferenceError(element);
       if (element is FieldElementImpl) {
+        _writeMarker(MarkerTag.VariableDeclaration_inheritsCovariant);
         _resolutionSink.writeByte(element.inheritsCovariant ? 1 : 0);
       }
     }
 
     Expression initializerToWrite;
-    if (_isConstField ||
-        _hasConstConstructor && _isFinalField ||
-        _isConstTopLevelVariable) {
+    if (_shouldStoreVariableInitializers) {
       var initializer = node.initializer;
       if (_isSerializableExpression(initializer)) {
         initializerToWrite = initializer;
       }
     }
+    _writeMarker(MarkerTag.VariableDeclaration_initializer);
     _writeOptionalNode(initializerToWrite);
+    _writeMarker(MarkerTag.VariableDeclaration_end);
   }
 
   @override
@@ -1544,15 +1820,21 @@
         isVar: node.keyword?.keyword == Keyword.VAR,
       ),
     );
+    _writeMarker(MarkerTag.VariableDeclarationList_type);
     _writeOptionalNode(node.type);
+    _writeMarker(MarkerTag.VariableDeclarationList_variables);
     _writeNodeList(node.variables);
+    _writeMarker(MarkerTag.VariableDeclarationList_annotatedNode);
     _storeAnnotatedNode(node);
+    _writeMarker(MarkerTag.VariableDeclarationList_end);
   }
 
   @override
   void visitWithClause(WithClause node) {
     _writeByte(Tag.WithClause);
+    _writeMarker(MarkerTag.WithClause_mixinTypes);
     _writeNodeList(node.mixinTypes);
+    _writeMarker(MarkerTag.WithClause_end);
   }
 
   void _pushScopeTypeParameters(TypeParameterList node) {
@@ -1572,10 +1854,13 @@
   }
 
   void _storeAnnotatedNode(AnnotatedNode node) {
+    _writeMarker(MarkerTag.AnnotatedNode_metadata);
     _writeNodeList(node.metadata);
+    _writeMarker(MarkerTag.AnnotatedNode_end);
   }
 
   void _storeClassMember(ClassMember node) {
+    _writeMarker(MarkerTag.ClassMember_declaration);
     _storeDeclaration(node);
   }
 
@@ -1583,8 +1868,6 @@
     _storeDeclaration(node);
   }
 
-  void _storeConstructorInitializer(ConstructorInitializer node) {}
-
   void _storeDeclaration(Declaration node) {
     _storeAnnotatedNode(node);
   }
@@ -1596,19 +1879,24 @@
 
   void _storeExpression(Expression node) {
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.Expression_staticType);
       _resolutionSink.writeType(node.staticType);
     }
   }
 
   void _storeForEachParts(ForEachParts node) {
+    _writeMarker(MarkerTag.ForEachParts_iterable);
     _writeNode(node.iterable);
+    _writeMarker(MarkerTag.ForEachParts_forLoopParts);
     _storeForLoopParts(node);
+    _writeMarker(MarkerTag.ForEachParts_end);
   }
 
   void _storeForLoopParts(ForLoopParts node) {}
 
   void _storeFormalParameter(FormalParameter node) {
     if (_shouldWriteResolution) {
+      _writeMarker(MarkerTag.FormalParameter_type);
       _writeActualType(node.declaredElement.type);
     }
   }
@@ -1619,19 +1907,28 @@
         hasAwait: node.awaitKeyword != null,
       ),
     );
+    _writeMarker(MarkerTag.ForMixin_forLoopParts);
     _writeNode(node.forLoopParts);
   }
 
   void _storeForParts(ForParts node) {
+    _writeMarker(MarkerTag.ForParts_condition);
     _writeOptionalNode(node.condition);
+    _writeMarker(MarkerTag.ForParts_updaters);
     _writeNodeList(node.updaters);
+    _writeMarker(MarkerTag.ForParts_forLoopParts);
     _storeForLoopParts(node);
+    _writeMarker(MarkerTag.ForParts_end);
   }
 
   void _storeInvocationExpression(InvocationExpression node) {
+    _writeMarker(MarkerTag.InvocationExpression_typeArguments);
     _writeOptionalNode(node.typeArguments);
+    _writeMarker(MarkerTag.InvocationExpression_argumentList);
     _writeNode(node.argumentList);
+    _writeMarker(MarkerTag.InvocationExpression_expression);
     _storeExpression(node);
+    _writeMarker(MarkerTag.InvocationExpression_end);
     // TODO(scheglov) typeArgumentTypes and staticInvokeType?
   }
 
@@ -1641,9 +1938,13 @@
   }
 
   void _storeNamespaceDirective(NamespaceDirective node) {
+    _writeMarker(MarkerTag.NamespaceDirective_combinators);
     _writeNodeList(node.combinators);
+    _writeMarker(MarkerTag.NamespaceDirective_configurations);
     _writeNodeList(node.configurations);
+    _writeMarker(MarkerTag.NamespaceDirective_uriBasedDirective);
     _storeUriBasedDirective(node);
+    _writeMarker(MarkerTag.NamespaceDirective_end);
   }
 
   void _storeNormalFormalParameter(
@@ -1667,11 +1968,14 @@
     _writeInformativeUint30(node.offset);
     _writeInformativeUint30(node.length);
 
+    _writeMarker(MarkerTag.NormalFormalParameter_metadata);
     _writeNodeList(node.metadata);
     if (node.identifier != null) {
       _writeDeclarationName(node.identifier);
     }
+    _writeMarker(MarkerTag.NormalFormalParameter_formalParameter);
     _storeFormalParameter(node);
+    _writeMarker(MarkerTag.NormalFormalParameter_end);
   }
 
   void _storeTypeAlias(TypeAlias node) {
@@ -1679,8 +1983,11 @@
   }
 
   void _storeUriBasedDirective(UriBasedDirective node) {
+    _writeMarker(MarkerTag.UriBasedDirective_uri);
     _writeNode(node.uri);
+    _writeMarker(MarkerTag.UriBasedDirective_directive);
     _storeDirective(node);
+    _writeMarker(MarkerTag.UriBasedDirective_end);
   }
 
   void _writeActualReturnType(DartType type) {
@@ -1789,6 +2096,14 @@
     }
   }
 
+  void _writeMarker(MarkerTag tag) {
+    if (enableDebugResolutionMarkers) {
+      if (_shouldWriteResolution) {
+        _resolutionSink.writeUInt30(tag.index);
+      }
+    }
+  }
+
   void _writeNode(AstNode node) {
     node.accept(this);
   }
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index a21430d..0925338 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -466,6 +466,10 @@
     }
   }
 
+  void writeUInt30(int value) {
+    _sink.writeUInt30(value);
+  }
+
   int _indexOfElement(Element element) {
     if (element == null) return 0;
     if (element is MultiplyDefinedElement) return 0;
diff --git a/pkg/analyzer/lib/src/summary2/default_value_resolver.dart b/pkg/analyzer/lib/src/summary2/default_value_resolver.dart
index a8398e4..1e49400 100644
--- a/pkg/analyzer/lib/src/summary2/default_value_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/default_value_resolver.dart
@@ -98,6 +98,11 @@
   }
 
   void _parameter(ParameterElementImpl parameter) {
+    // If a function typed parameter, process nested parameters.
+    for (var localParameter in parameter.parameters) {
+      _parameter(localParameter);
+    }
+
     var node = _defaultParameter(parameter);
     if (node == null) return;
 
diff --git a/pkg/analyzer/lib/src/summary2/variance_builder.dart b/pkg/analyzer/lib/src/summary2/variance_builder.dart
index 755f4c9..1dc486d 100644
--- a/pkg/analyzer/lib/src/summary2/variance_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/variance_builder.dart
@@ -59,15 +59,16 @@
       }
     } else if (type is NamedTypeBuilder) {
       var element = type.element;
+      var arguments = type.arguments;
       if (element is ClassElement) {
         var result = Variance.unrelated;
-        if (type.arguments.isNotEmpty) {
+        if (arguments.isNotEmpty) {
           var parameters = element.typeParameters;
-          for (int i = 0; i < type.arguments.length; ++i) {
+          for (var i = 0; i < arguments.length && i < parameters.length; i++) {
             var parameter = parameters[i] as TypeParameterElementImpl;
             result = result.meet(
               parameter.variance.combine(
-                _compute(variable, type.arguments[i]),
+                _compute(variable, arguments[i]),
               ),
             );
           }
@@ -78,14 +79,14 @@
 
         var result = Variance.unrelated;
 
-        if (type.arguments.isNotEmpty) {
+        if (arguments.isNotEmpty) {
           var parameters = element.typeParameters;
-          for (var i = 0; i < type.arguments.length; ++i) {
+          for (var i = 0; i < arguments.length && i < parameters.length; i++) {
             var parameter = parameters[i] as TypeParameterElementImpl;
             var parameterVariance = parameter.variance;
             result = result.meet(
               parameterVariance.combine(
-                _compute(variable, type.arguments[i]),
+                _compute(variable, arguments[i]),
               ),
             );
           }
diff --git a/pkg/analyzer/test/file_system/file_system_test_support.dart b/pkg/analyzer/test/file_system/file_system_test_support.dart
index 96db954..adf8754 100644
--- a/pkg/analyzer/test/file_system/file_system_test_support.dart
+++ b/pkg/analyzer/test/file_system/file_system_test_support.dart
@@ -124,7 +124,7 @@
 
   test_equals_samePath() {
     File file1 = getFile(exists: true);
-    File file2 = provider.getResource(file1.path);
+    var file2 = provider.getResource(file1.path) as File;
 
     expect(file1 == file2, isTrue);
   }
@@ -143,7 +143,7 @@
 
   test_hashCode_samePath() {
     File file1 = getFile(exists: true);
-    File file2 = provider.getResource(file1.path);
+    var file2 = provider.getResource(file1.path) as File;
 
     expect(file1.hashCode, equals(file2.hashCode));
   }
diff --git a/pkg/analyzer/test/generated/elements_types_mixin.dart b/pkg/analyzer/test/generated/elements_types_mixin.dart
index c139b6e..6089f5a 100644
--- a/pkg/analyzer/test/generated/elements_types_mixin.dart
+++ b/pkg/analyzer/test/generated/elements_types_mixin.dart
@@ -296,7 +296,7 @@
     ) as InterfaceTypeImpl;
   }
 
-  DartType futureType(DartType T) {
+  InterfaceType futureType(DartType T) {
     var futureElement = typeProvider.futureElement;
     return interfaceTypeStar(futureElement, typeArguments: [T]);
   }
@@ -378,8 +378,8 @@
   LibraryElementImpl library_({
     @required String uriStr,
     @required TypeSystemImpl typeSystem,
-    AnalysisContext analysisContext,
-    AnalysisSessionImpl analysisSession,
+    @required AnalysisContext analysisContext,
+    @required AnalysisSessionImpl analysisSession,
   }) {
     var library = LibraryElementImpl(
       analysisContext,
diff --git a/pkg/analyzer/test/generated/invalid_code_test.dart b/pkg/analyzer/test/generated/invalid_code_test.dart
index 6fd7955..95d6713 100644
--- a/pkg/analyzer/test/generated/invalid_code_test.dart
+++ b/pkg/analyzer/test/generated/invalid_code_test.dart
@@ -389,6 +389,39 @@
 @reflectiveTest
 class InvalidCodeWithNullSafetyTest extends PubPackageResolutionTest
     with WithNullSafetyMixin {
+  test_functionExpression_emptyBody() async {
+    await _assertCanBeAnalyzed(r'''
+var v = <T>();
+''');
+  }
+
+  test_functionExpressionInvocation_mustBeNullShortingTerminated() async {
+    // It looks like MethodInvocation, but because `8` is not SimpleIdentifier,
+    // we parse it as FunctionExpressionInvocation.
+    await _assertCanBeAnalyzed(r'''
+var v = a?.8(b);
+''');
+  }
+
+  test_inAnnotation_noFlow_labeledStatement() async {
+    await _assertCanBeAnalyzed('''
+@A(() { label: })
+typedef F = void Function();
+''');
+  }
+
+  test_inDefaultValue_noFlow_ifExpression() async {
+    await _assertCanBeAnalyzed('''
+typedef void F({a = [if (true) 0]});
+''');
+  }
+
+  test_inDefaultValue_noFlow_ifStatement() async {
+    await _assertCanBeAnalyzed('''
+typedef void F([a = () { if (true) 0; }]);
+''');
+  }
+
   test_issue_40837() async {
     await _assertCanBeAnalyzed('''
 class A {
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 05d5f54..9a1c27b 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -2075,10 +2075,9 @@
       source,
       isNonNullableByDefault: false,
     );
-    fasta.Parser parser = fasta.Parser(null);
     AstBuilder astBuilder =
         AstBuilder(errorReporter, source.uri, true, featureSet);
-    parser.listener = astBuilder;
+    fasta.Parser parser = fasta.Parser(astBuilder);
     astBuilder.parser = parser;
     astBuilder.allowNativeClause = allowNativeClause;
     parser.parseUnit(_fastaTokens);
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index 639ce65..c0c874f 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -173,7 +173,8 @@
     int count = expectedLocations.length;
     for (int i = 0; i < count; i++) {
       ScannerTest_ExpectedLocation expectedLocation = expectedLocations[i];
-      CharacterLocation location = info.getLocation(expectedLocation._offset);
+      var location =
+          info.getLocation(expectedLocation._offset) as CharacterLocation;
       expect(location.lineNumber, expectedLocation._lineNumber,
           reason: 'Line number in location $i');
       expect(location.columnNumber, expectedLocation._columnNumber,
diff --git a/pkg/analyzer/test/generated/source_factory_test.dart b/pkg/analyzer/test/generated/source_factory_test.dart
index 3ec4b21..3282f36 100644
--- a/pkg/analyzer/test/generated/source_factory_test.dart
+++ b/pkg/analyzer/test/generated/source_factory_test.dart
@@ -21,12 +21,6 @@
   });
 }
 
-Source createSource({String path, String uri}) =>
-    //TODO(pquitslund): find some way to pass an actual URI into source creation
-    MemoryResourceProvider()
-        .getFile(path)
-        .createSource(uri != null ? Uri.parse(uri) : null);
-
 class AbsoluteUriResolver extends UriResolver {
   final MemoryResourceProvider resourceProvider;
 
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index 3c0dd2d..0d06335 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -48,6 +48,7 @@
 
     testLibrary = library_(
       uriStr: 'package:test/test.dart',
+      analysisContext: analysisContext,
       analysisSession: analysisContext.analysisSession,
       typeSystem: typeSystem,
     );
@@ -78,6 +79,7 @@
 
     testLibrary = library_(
       uriStr: 'package:test/test.dart',
+      analysisContext: analysisContext,
       analysisSession: analysisContext.analysisSession,
       typeSystem: typeSystem,
     );
diff --git a/pkg/analyzer/test/id_tests/type_promotion_test.dart b/pkg/analyzer/test/id_tests/type_promotion_test.dart
index 54d8d09..177ce59 100644
--- a/pkg/analyzer/test/id_tests/type_promotion_test.dart
+++ b/pkg/analyzer/test/id_tests/type_promotion_test.dart
@@ -54,8 +54,8 @@
     if (node is SimpleIdentifier && node.inGetterContext()) {
       var element = _readElement(node);
       if (element is LocalVariableElement || element is ParameterElement) {
-        TypeImpl promotedType = _readType(node);
-        TypeImpl declaredType = (element as VariableElement).type;
+        var promotedType = _readType(node) as TypeImpl;
+        var declaredType = (element as VariableElement).type as TypeImpl;
         var isPromoted = promotedType != declaredType;
         if (isPromoted) {
           return promotedType;
diff --git a/pkg/analyzer/test/source/analysis_options_provider_test.dart b/pkg/analyzer/test/source/analysis_options_provider_test.dart
index 9e4eb9a..810d8d2 100644
--- a/pkg/analyzer/test/source/analysis_options_provider_test.dart
+++ b/pkg/analyzer/test/source/analysis_options_provider_test.dart
@@ -101,10 +101,10 @@
 
 @reflectiveTest
 class AnalysisOptionsProviderTest {
-  TestPathTranslator pathTranslator;
-  ResourceProvider resourceProvider;
+  /*late*/ TestPathTranslator pathTranslator;
+  /*late*/ ResourceProvider resourceProvider;
 
-  AnalysisOptionsProvider provider;
+  /*late*/ AnalysisOptionsProvider provider;
 
   String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
 
@@ -132,7 +132,7 @@
     YamlMap options = _getOptions('/foo/bar', crawlUp: true);
     expect(options, hasLength(1));
     {
-      YamlMap analyzer = getValue(options, 'analyzer');
+      var analyzer = getValue(options, 'analyzer') as YamlMap;
       expect(analyzer, isNotNull);
       expect(getValue(analyzer, 'ignore'), unorderedEquals(['bar']));
     }
@@ -153,7 +153,7 @@
     YamlMap options = _getOptions('/foo/bar/baz', crawlUp: true);
     expect(options, hasLength(1));
     {
-      YamlMap analyzer = getValue(options, 'analyzer');
+      var analyzer = getValue(options, 'analyzer') as YamlMap;
       expect(analyzer, isNotNull);
       expect(getValue(analyzer, 'ignore'), unorderedEquals(['bar']));
     }
@@ -185,10 +185,10 @@
     YamlMap options = _getOptions('/');
     expect(options, hasLength(2));
     {
-      YamlMap analyzer = getValue(options, 'analyzer');
+      var analyzer = getValue(options, 'analyzer') as YamlMap;
       expect(analyzer, hasLength(1));
       {
-        YamlList ignore = getValue(analyzer, 'ignore');
+        var ignore = getValue(analyzer, 'ignore') as YamlList;
         expect(ignore, hasLength(2));
         expect(ignore[0], 'ignoreme.dart');
         expect(ignore[1], 'sdk_ext/**');
@@ -220,10 +220,10 @@
     YamlMap options = _getOptions('/');
     expect(options, hasLength(1));
     {
-      YamlMap analyzer = getValue(options, 'analyzer');
+      var analyzer = getValue(options, 'analyzer') as YamlMap;
       expect(analyzer, hasLength(1));
       {
-        YamlList ignore = getValue(analyzer, 'ignore');
+        var ignore = getValue(analyzer, 'ignore') as YamlList;
         expect(ignore, hasLength(2));
         expect(ignore[0], 'ignoreme.dart');
         expect(ignore[1], 'sdk_ext/**');
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
index 30433aa..31db512 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
@@ -22,6 +22,47 @@
     return driver.test.libraryContext.linkedCycles;
   }
 
+  test_change_field_staticFinal_hasConstConstructor_changeInitializer() async {
+    useEmptyByteStore();
+
+    newFile(testFilePath, content: r'''
+class A {
+  static const a = 0;
+  static const b = 1;
+  static final Set<int> f = {a};
+  const A {}
+}
+''');
+
+    await resolveTestFile();
+    assertType(findElement.field('f').type, 'Set<int>');
+
+    // The summary for the library was linked.
+    _assertContainsLinkedCycle({testFilePath}, andClear: true);
+
+    // Dispose the collection, with its driver.
+    // The next analysis will recreate it.
+    // We will reuse the byte store, so can reuse summaries.
+    disposeAnalysisContextCollection();
+
+    newFile(testFilePath, content: r'''
+class A {
+  static const a = 0;
+  static const b = 1;
+  static final Set<int> f = <int>{a, b, 2};
+  const A {}
+}
+''');
+
+    await resolveTestFile();
+    assertType(findElement.field('f').type, 'Set<int>');
+
+    // We changed the initializer of the final field. But it is static, so
+    // even though the class hsa a constant constructor, we don't need its
+    // initializer, so nothing should be linked.
+    _assertNoLinkedCycles();
+  }
+
   test_change_functionBody() async {
     useEmptyByteStore();
 
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index b4e5635..167c6d5 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -58,6 +58,7 @@
 
     testLibrary = library_(
       uriStr: 'package:test/test.dart',
+      analysisContext: _analysisContext,
       analysisSession: _analysisContext.analysisSession,
       typeSystem: typeSystem,
     );
diff --git a/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart b/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart
index 63715f5..94d6e21 100644
--- a/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart
+++ b/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart
@@ -20,10 +20,10 @@
 
 @reflectiveTest
 class TypeConstraintGathererTest extends AbstractTypeSystemNullSafetyTest {
-  TypeParameterElement T;
-  TypeParameterType T_none;
-  TypeParameterType T_question;
-  TypeParameterType T_star;
+  /*late*/ TypeParameterElement T;
+  /*late*/ TypeParameterType T_none;
+  /*late*/ TypeParameterType T_question;
+  /*late*/ TypeParameterType T_star;
 
   UnknownInferredType get unknownType => UnknownInferredType.instance;
 
@@ -681,6 +681,7 @@
     ) {
       var library = library_(
         uriStr: 'package:test/test.dart',
+        analysisContext: analysisContext,
         analysisSession: analysisContext.analysisSession,
         typeSystem: typeSystem,
       );
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
index d7f4445..2149a04 100644
--- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
@@ -39,12 +39,12 @@
   final bool strictRawTypes;
 
   AnalysisOptionsFileConfig({
-    this.experiments,
-    this.implicitCasts,
-    this.implicitDynamic,
-    this.lints,
-    this.strictInference,
-    this.strictRawTypes,
+    this.experiments = const [],
+    this.implicitCasts = true,
+    this.implicitDynamic = true,
+    this.lints = const [],
+    this.strictInference = false,
+    this.strictRawTypes = false,
   });
 
   String toContent() {
diff --git a/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart b/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
index 71c3ecb..f743dcf 100644
--- a/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
@@ -148,7 +148,7 @@
 
 typedef G<T> = T Function(double);
 ''');
-    FunctionType type = findElement.topVar('g').type;
+    var type = findElement.topVar('g').type as FunctionType;
     assertType(type, 'int Function(double)');
 
     var typedefG = findElement.functionTypeAlias('G');
diff --git a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
index fc67be62..7558067 100644
--- a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
@@ -29,6 +29,19 @@
     );
   }
 
+  test_invalid_inDefaultValue_nullAware2() async {
+    await assertInvalidTestCode(r'''
+typedef void F({a = b?[0]});
+''');
+
+    assertIndexExpression(
+      findNode.index('[0]'),
+      readElement: null,
+      writeElement: null,
+      type: 'dynamic',
+    );
+  }
+
   test_read() async {
     await assertNoErrorsInCode(r'''
 class A {
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 4421117e..9750759 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -1622,7 +1622,7 @@
     assertElement(foo.propertyName, import.class_('C').getGetter('foo'));
     assertType(foo.propertyName, 'double Function(int)');
 
-    PrefixedIdentifier target = foo.target;
+    var target = foo.target as PrefixedIdentifier;
     assertImportPrefix(target.prefix, import.prefix);
     assertClassRef(target.identifier, import.class_('C'));
   }
@@ -1651,7 +1651,7 @@
       'void Function(int)',
     );
 
-    PrefixedIdentifier target = invocation.target;
+    var target = invocation.target as PrefixedIdentifier;
     assertImportPrefix(target.prefix, import.prefix);
     assertClassRef(target.identifier, import.class_('C'));
   }
@@ -1718,6 +1718,20 @@
     );
   }
 
+  test_invalid_inDefaultValue_nullAware2() async {
+    await assertInvalidTestCode('''
+typedef void F({a = b?.foo()});
+''');
+
+    assertMethodInvocation2(
+      findNode.methodInvocation('?.foo()'),
+      element: null,
+      typeArgumentTypes: [],
+      invokeType: 'dynamic',
+      type: 'dynamic',
+    );
+  }
+
   test_namedArgument() async {
     var question = typeToStringWithNullability ? '?' : '';
     await assertNoErrorsInCode('''
diff --git a/pkg/analyzer/test/src/dart/resolution/optional_const_test.dart b/pkg/analyzer/test/src/dart/resolution/optional_const_test.dart
index cb554a1b..cd08b22 100644
--- a/pkg/analyzer/test/src/dart/resolution/optional_const_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/optional_const_test.dart
@@ -196,10 +196,10 @@
 ''');
     _fillLibraries();
 
-    PropertyAccessorElement vg = findNode.simple('a;').staticElement;
+    var vg = findNode.simple('a;').staticElement as PropertyAccessorElement;
     var v = vg.variable as ConstVariableElement;
 
-    InstanceCreationExpression creation = v.constantInitializer;
+    InstanceCreationExpression /*!*/ creation = v.constantInitializer;
     return creation;
   }
 }
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 645d77a..e1724a4 100644
--- a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
@@ -250,6 +250,18 @@
     );
   }
 
+  test_invalid_inDefaultValue_nullAware2() async {
+    await assertInvalidTestCode('''
+typedef void F({a = b?.foo});
+''');
+
+    assertPropertyAccess2(
+      findNode.propertyAccess('?.foo'),
+      element: null,
+      type: 'dynamic',
+    );
+  }
+
   test_invalid_inDefaultValue_nullAware_cascade() async {
     await assertInvalidTestCode('''
 void f({a = b?..foo}) {}
diff --git a/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart b/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
index 699a2a5..25b5b05 100644
--- a/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
@@ -375,7 +375,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*, int*)*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.topGet('foo'));
   }
 
@@ -400,7 +400,7 @@
     var identifier = invocation.function;
     assertType(identifier, 'A*');
 
-    MethodElement element = invocation.staticElement;
+    var element = invocation.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('call'));
   }
 
@@ -425,7 +425,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*)*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.getter('foo'));
   }
 
@@ -512,7 +512,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('foo'));
   }
 
@@ -537,7 +537,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('foo'));
   }
 
@@ -565,7 +565,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('foo'));
   }
 
@@ -590,7 +590,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('foo'));
   }
 
@@ -615,7 +615,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('foo'));
   }
 
@@ -638,7 +638,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*, int*)*');
 
-    FunctionElement element = identifier.staticElement;
+    var element = identifier.staticElement as FunctionElement;
     _assertLegacyMember(element, _import_a.topFunction('foo'));
   }
 
@@ -661,7 +661,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*, int*)*');
 
-    FunctionElement element = identifier.staticElement;
+    var element = identifier.staticElement as FunctionElement;
     _assertLegacyMember(element, _import_a.topFunction('foo'));
   }
 
@@ -686,7 +686,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*, int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     assertType(element.type, 'int* Function(int*, int*)*');
   }
 
@@ -711,7 +711,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*, int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     assertType(element.type, 'int* Function(int*, int*)*');
   }
 
@@ -738,7 +738,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*, int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     assertType(element.type, 'int* Function(int*, int*)*');
   }
 
@@ -763,7 +763,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*, int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     assertType(element.type, 'int* Function(int*, int*)*');
   }
 
@@ -790,7 +790,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*, int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     assertType(element.type, 'int* Function(int*, int*)*');
   }
 
@@ -904,7 +904,7 @@
     var identifier = prefixedIdentifier.identifier;
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.getter('foo'));
   }
 
@@ -929,7 +929,7 @@
     var identifier = prefixedIdentifier.identifier;
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.getter('foo'));
   }
 
@@ -953,7 +953,7 @@
     var identifier = prefixedIdentifier.identifier;
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.getter('foo'));
   }
 
@@ -977,7 +977,7 @@
     var identifier = prefixedIdentifier.identifier;
     assertType(identifier, 'int* Function(int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('foo'));
   }
 
@@ -1001,7 +1001,7 @@
     var identifier = prefixedIdentifier.identifier;
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.getter('foo'));
   }
 
@@ -1025,7 +1025,7 @@
     var identifier = prefixedIdentifier.identifier;
     assertType(identifier, 'int* Function(int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('foo'));
   }
 
@@ -1047,7 +1047,7 @@
     var identifier = prefixedIdentifier.identifier;
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.topGet('foo'));
   }
 
@@ -1071,7 +1071,7 @@
     var identifier = propertyAccess.propertyName;
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.getter('foo'));
   }
 
@@ -1095,7 +1095,7 @@
     var identifier = propertyAccess.propertyName;
     assertType(identifier, 'int* Function()*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('foo'));
   }
 
@@ -1120,7 +1120,7 @@
     var identifier = propertyAccess.propertyName;
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.getter('foo'));
   }
 
@@ -1146,7 +1146,7 @@
     var identifier = propertyAccess.propertyName;
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.getter('foo'));
   }
 
@@ -1169,7 +1169,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.getter('foo'));
   }
 
@@ -1192,7 +1192,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('foo'));
   }
 
@@ -1216,7 +1216,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.getter('foo'));
   }
 
@@ -1240,7 +1240,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int* Function(int*)*');
 
-    MethodElement element = identifier.staticElement;
+    var element = identifier.staticElement as MethodElement;
     _assertLegacyMember(element, _import_a.method('foo'));
   }
 
@@ -1259,7 +1259,7 @@
     var identifier = findNode.simple('foo');
     assertType(identifier, 'int*');
 
-    PropertyAccessorElement element = identifier.staticElement;
+    var element = identifier.staticElement as PropertyAccessorElement;
     _assertLegacyMember(element, _import_a.topGet('foo'));
   }
 
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 8703b9d..b4af040 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -301,16 +301,17 @@
     var initializers = (e as ConstructorElementImpl).constantInitializers;
     if (withFullyResolvedAst) {
       buffer.writeln(';');
-      if (initializers != null && initializers.isNotEmpty) {
-        _withIndent(() {
+      _withIndent(() {
+        if (initializers != null && initializers.isNotEmpty) {
           _writelnWithIndent('constantInitializers');
           _withIndent(() {
             for (var initializer in initializers) {
               _writeResolvedNode(initializer);
             }
           });
-        });
-      }
+        }
+        _writeParameterElementDefaultValues(e.parameters);
+      });
     } else {
       if (initializers != null) {
         writeList(' : ', '', initializers, ', ', writeNode);
@@ -407,6 +408,12 @@
     writeBodyModifiers(e);
 
     buffer.writeln(' {}');
+
+    if (withFullyResolvedAst) {
+      _withIndent(() {
+        _writeParameterElementDefaultValues(e.parameters);
+      });
+    }
   }
 
   void writeIf(bool flag, String str) {
@@ -530,6 +537,7 @@
       _withIndent(() {
         _writeResolvedTypeParameters(e.typeParameters);
         _writeResolvedMetadata(e.metadata);
+        _writeParameterElementDefaultValues(e.parameters);
       });
     }
   }
@@ -828,15 +836,17 @@
     writeName(e);
     writeCodeRange(e);
 
-    if (e.parameters.isNotEmpty) {
-      buffer.write('/*');
-      writeList('(', ')', e.parameters, ', ', writeParameterElement);
-      buffer.write('*/');
-    }
+    if (!withFullyResolvedAst) {
+      if (e.parameters.isNotEmpty) {
+        buffer.write('/*');
+        writeList('(', ')', e.parameters, ', ', writeParameterElement);
+        buffer.write('*/');
+      }
 
-    if (defaultValue != null) {
-      buffer.write(defaultValueSeparator);
-      writeNode(defaultValue);
+      if (defaultValue != null) {
+        buffer.write(defaultValueSeparator);
+        writeNode(defaultValue);
+      }
     }
 
     buffer.write(closeString);
@@ -1194,6 +1204,30 @@
     buffer.writeln(line);
   }
 
+  void _writeParameterElementDefaultValues(
+    List<ParameterElement> parameters, {
+    String enclosingNames = '',
+  }) {
+    for (var parameter in parameters) {
+      if (parameter is DefaultParameterElementImpl) {
+        var defaultValue = parameter.constantInitializer;
+        if (defaultValue != null) {
+          _writelnWithIndent(enclosingNames + parameter.name);
+          _withIndent(() {
+            _writeResolvedNode(defaultValue);
+          });
+        }
+      }
+      var subParameters = parameter.parameters;
+      _withIndent(() {
+        _writeParameterElementDefaultValues(
+          subParameters,
+          enclosingNames: enclosingNames + parameter.name + '::',
+        );
+      });
+    }
+  }
+
   void _writeResolvedMetadata(List<ElementAnnotation> metadata) {
     if (metadata.isNotEmpty) {
       _writelnWithIndent('metadata');
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 66e02fa..3e5d249 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -4440,13 +4440,30 @@
   a?.length,
 ];
 ''');
-    // TODO(scheglov) include fully resolved AST, when types with suffixes
-    checkElementText(library, r'''
-const String? a = '';
-const List<int?> b = [
-        a/*location: test.dart;a?*/.
-        length/*location: dart:core;String;length?*/];
-''');
+    checkElementText(
+        library,
+        r'''
+const String? a;
+  constantInitializer
+    SimpleStringLiteral
+      literal: ''
+const List<int?> b;
+  constantInitializer
+    ListLiteral
+      elements
+        PropertyAccess
+          propertyName: SimpleIdentifier
+            staticElement: dart:core::@class::String::@getter::length
+            staticType: int
+            token: length
+          staticType: int?
+          target: SimpleIdentifier
+            staticElement: self::@getter::a
+            staticType: String?
+            token: a
+      staticType: List<int?>
+''',
+        withFullyResolvedAst: true);
   }
 
   test_const_topLevel_parenthesis() async {
@@ -4815,7 +4832,7 @@
         r'''
 class A {
   final int _f;
-  const A([int f = 0]);
+  const A([int f]);
     constantInitializers
       ConstructorFieldInitializer
         equals: =
@@ -4827,6 +4844,10 @@
           staticElement: self::@class::A::@field::_f
           staticType: null
           token: _f
+    f
+      IntegerLiteral
+        literal: 0
+        staticType: int
 }
 ''',
         withFullyResolvedAst: true);
@@ -5583,6 +5604,30 @@
 ''');
   }
 
+  test_defaultValue_inFunctionTypedFormalParameter() async {
+    var library = await checkLibrary('''
+void f( g({a: 0 is int}) ) {}
+''');
+    checkElementText(
+        library,
+        r'''
+void f(dynamic Function({dynamic a}) g) {}
+    g::a
+      IsExpression
+        expression: IntegerLiteral
+          literal: 0
+          staticType: int
+        staticType: bool
+        type: TypeName
+          name: SimpleIdentifier
+            staticElement: dart:core::@class::int
+            staticType: null
+            token: int
+          type: int
+''',
+        withFullyResolvedAst: true);
+  }
+
   test_defaultValue_refersToExtension_method_inside() async {
     var library = await checkLibrary('''
 class A {}
@@ -7577,6 +7622,35 @@
         withTypeParameterVariance: true);
   }
 
+  test_genericTypeAlias_typeParameters_variance_invalid() async {
+    var library = await checkLibrary(r'''
+class A {}
+typedef F<T> = void Function(A<int>);
+''');
+    checkElementText(
+        library,
+        r'''
+typedef F<unrelated T> = void Function(A );
+class A {
+}
+''',
+        withTypeParameterVariance: true);
+  }
+
+  test_genericTypeAlias_typeParameters_variance_invalid2() async {
+    var library = await checkLibrary(r'''
+typedef F = void Function();
+typedef G<T> = void Function(F<int>);
+''');
+    checkElementText(
+        library,
+        r'''
+typedef F = void Function();
+typedef G<unrelated T> = void Function(void Function() );
+''',
+        withTypeParameterVariance: true);
+  }
+
   test_genericTypeAlias_typeParameters_variance_invariant() async {
     var library = await checkLibrary(r'''
 typedef F<T> = T Function(T);
@@ -9501,6 +9575,62 @@
 ''');
   }
 
+  test_metadata_constructor_call_named_synthetic_ofClassAlias_generic() async {
+    var library = await checkLibrary('''
+class A {
+  const A.named();
+}
+
+mixin B {}
+
+class C<T> = A with B; 
+
+@C.named()
+class D {}
+''');
+    checkElementText(
+        library,
+        r'''
+class A {
+  const A.named();
+}
+class alias C extends A with B {
+  synthetic const C.named() = A.named;
+}
+  typeParameters
+    T
+      bound: null
+      defaultType: dynamic
+class D {
+}
+  metadata
+    Annotation
+      arguments: ArgumentList
+      element: ConstructorMember
+        base: self::@class::C::@constructor::named
+        substitution: {T: dynamic}
+      name: PrefixedIdentifier
+        identifier: SimpleIdentifier
+          staticElement: ConstructorMember
+            base: self::@class::C::@constructor::named
+            substitution: {T: dynamic}
+          staticType: null
+          token: named
+        period: .
+        prefix: SimpleIdentifier
+          staticElement: self::@class::C
+          staticType: null
+          token: C
+        staticElement: ConstructorMember
+          base: self::@class::C::@constructor::named
+          substitution: {T: dynamic}
+        staticType: null
+mixin B on Object {
+}
+''',
+        withFullyResolvedAst: true);
+  }
+
   test_metadata_constructor_call_unnamed() async {
     var library = await checkLibrary('class A { const A(); } @A() class C {}');
     checkElementText(library, r'''
@@ -9528,6 +9658,50 @@
 ''');
   }
 
+  test_metadata_constructor_call_unnamed_synthetic_ofClassAlias_generic() async {
+    var library = await checkLibrary('''
+class A {
+  const A();
+}
+
+mixin B {}
+
+class C<T> = A with B; 
+
+@C()
+class D {}
+''');
+    checkElementText(
+        library,
+        r'''
+class A {
+  const A();
+}
+class alias C extends A with B {
+  synthetic const C() = A;
+}
+  typeParameters
+    T
+      bound: null
+      defaultType: dynamic
+class D {
+}
+  metadata
+    Annotation
+      arguments: ArgumentList
+      element: ConstructorMember
+        base: self::@class::C::@constructor::•
+        substitution: {T: dynamic}
+      name: SimpleIdentifier
+        staticElement: self::@class::C
+        staticType: null
+        token: C
+mixin B on Object {
+}
+''',
+        withFullyResolvedAst: true);
+  }
+
   test_metadata_constructor_call_with_args() async {
     var library =
         await checkLibrary('class A { const A(x); } @A(null) class C {}');
@@ -11957,7 +12131,6 @@
 ''');
   }
 
-  /// TODO(scheglov) add `?` cases.
   test_typedef_nonFunction_asInterfaceType_interfaceType_none() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
@@ -11974,24 +12147,95 @@
 ''');
   }
 
-  @failingTest
   test_typedef_nonFunction_asInterfaceType_interfaceType_question() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
 typedef X<T> = A<T>?;
 class A<T> {}
-class B implements X<int> {}
+class B {}
+class C {}
+class D implements B, X<int>, C {}
 ''');
     checkElementText(library, r'''
-typedef X<T> = A<int, T>;
-class A<T, U> {
+typedef X<T> = A<T>?;
+class A<T> {
 }
-class B implements A<int, String> {
+class B {
+}
+class C {
+}
+class D implements B, C {
 }
 ''');
   }
 
-  /// TODO(scheglov) add `?` cases.
+  test_typedef_nonFunction_asInterfaceType_interfaceType_question2() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X<T> = A<T?>;
+class A<T> {}
+class B {}
+class C {}
+class D implements B, X<int>, C {}
+''');
+    checkElementText(library, r'''
+typedef X<T> = A<T?>;
+class A<T> {
+}
+class B {
+}
+class C {
+}
+class D implements B, A<int?>, C {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asInterfaceType_Never_none() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X = Never;
+class A implements X {}
+''');
+    checkElementText(library, r'''
+typedef X = Never;
+class A {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asInterfaceType_Null_none() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X = Null;
+class A implements X {}
+''');
+    checkElementText(library, r'''
+typedef X = Null;
+class A {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asInterfaceType_typeParameterType() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X<T> = T;
+class A {}
+class B {}
+class C<U> implements A, X<U>, B {}
+''');
+    checkElementText(library, r'''
+typedef X<T> = T;
+class A {
+}
+class B {
+}
+class C<U> implements A, B {
+}
+''');
+  }
+
   test_typedef_nonFunction_asInterfaceType_void() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
@@ -12011,8 +12255,7 @@
 ''');
   }
 
-  /// TODO(scheglov) add `?` cases.
-  test_typedef_nonFunction_asMixinType() async {
+  test_typedef_nonFunction_asMixinType_none() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
 typedef X = A<int>;
@@ -12029,8 +12272,66 @@
 ''');
   }
 
-  /// TODO(scheglov) add `?` cases.
-  test_typedef_nonFunction_asSuperType_interfaceType() async {
+  test_typedef_nonFunction_asMixinType_question() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X = A<int>?;
+class A<T> {}
+mixin M1 {}
+mixin M2 {}
+class B with M1, X, M2 {}
+''');
+    checkElementText(library, r'''
+typedef X = A<int>?;
+class A<T> {
+}
+class B extends Object with M1, M2 {
+  synthetic B();
+}
+mixin M1 on Object {
+}
+mixin M2 on Object {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asMixinType_question2() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X = A<int?>;
+class A<T> {}
+mixin M1 {}
+mixin M2 {}
+class B with M1, X, M2 {}
+''');
+    checkElementText(library, r'''
+typedef X = A<int?>;
+class A<T> {
+}
+class B extends Object with M1, A<int?>, M2 {
+  synthetic B();
+}
+mixin M1 on Object {
+}
+mixin M2 on Object {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asSuperType_interfaceType_Never_none() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X = Never;
+class A extends X {}
+''');
+    checkElementText(library, r'''
+typedef X = Never;
+class A {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asSuperType_interfaceType_none() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
 typedef X = A<int>;
@@ -12046,7 +12347,93 @@
 ''');
   }
 
-  /// TODO(scheglov) add `?` cases.
+  test_typedef_nonFunction_asSuperType_interfaceType_none_viaTypeParameter() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X<T> = T;
+class A<T> {}
+class B extends X<A<int>> {}
+''');
+    checkElementText(library, r'''
+typedef X<T> = T;
+class A<T> {
+}
+class B extends A<int> {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asSuperType_interfaceType_Null_none() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X = Null;
+class A extends X {}
+''');
+    checkElementText(library, r'''
+typedef X = Null;
+class A {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asSuperType_interfaceType_question() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X = A<int>?;
+class A<T> {}
+class D extends X {}
+''');
+    checkElementText(library, r'''
+typedef X = A<int>?;
+class A<T> {
+}
+class D {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asSuperType_interfaceType_question2() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X = A<int?>;
+class A<T> {}
+class D extends X {}
+''');
+    checkElementText(library, r'''
+typedef X = A<int?>;
+class A<T> {
+}
+class D extends A<int?> {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asSuperType_Never_none() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X = Never;
+class A extends X {}
+''');
+    checkElementText(library, r'''
+typedef X = Never;
+class A {
+}
+''');
+  }
+
+  test_typedef_nonFunction_asSuperType_Null_none() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef X = Null;
+class A extends X {}
+''');
+    checkElementText(library, r'''
+typedef X = Null;
+class A {
+}
+''');
+  }
+
   test_typedef_nonFunction_using_dynamic() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
@@ -12086,6 +12473,18 @@
 ''');
   }
 
+  test_typedef_nonFunction_using_interface_noTypeParameters_question() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef A = int?;
+void f(A a) {}
+''');
+    checkElementText(library, r'''
+typedef A = int?;
+void f(int? a) {}
+''');
+  }
+
   test_typedef_nonFunction_using_interface_withTypeParameters() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
@@ -12098,8 +12497,7 @@
 ''');
   }
 
-  /// TODO(scheglov) add `?` cases.
-  test_typedef_nonFunction_using_Never() async {
+  test_typedef_nonFunction_using_Never_none() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
 typedef A = Never;
@@ -12111,8 +12509,19 @@
 ''');
   }
 
-  /// TODO(scheglov) add `?` cases.
-  test_typedef_nonFunction_using_typeParameter() async {
+  test_typedef_nonFunction_using_Never_question() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef A = Never?;
+void f(A a) {}
+''');
+    checkElementText(library, r'''
+typedef A = Never?;
+void f(Never? a) {}
+''');
+  }
+
+  test_typedef_nonFunction_using_typeParameter_none() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
 typedef A<T> = T;
@@ -12126,7 +12535,20 @@
 ''');
   }
 
-  /// TODO(scheglov) add `?` cases.
+  test_typedef_nonFunction_using_typeParameter_question() async {
+    featureSet = FeatureSets.nonFunctionTypeAliases;
+    var library = await checkLibrary(r'''
+typedef A<T> = T?;
+void f1(A a) {}
+void f2(A<int> a) {}
+''');
+    checkElementText(library, r'''
+typedef A<T> = T?;
+void f1(dynamic a) {}
+void f2(int? a) {}
+''');
+  }
+
   test_typedef_nonFunction_using_void() async {
     featureSet = FeatureSets.nonFunctionTypeAliases;
     var library = await checkLibrary(r'''
diff --git a/pkg/analyzer/tool/summary/mini_ast.dart b/pkg/analyzer/tool/summary/mini_ast.dart
index 1993ae8..356e81f 100644
--- a/pkg/analyzer/tool/summary/mini_ast.dart
+++ b/pkg/analyzer/tool/summary/mini_ast.dart
@@ -576,7 +576,7 @@
   }
 
   @override
-  dynamic internalProblem(Message message, int charOffset, Uri uri) {
+  internalProblem(Message message, int charOffset, Uri uri) {
     throw UnsupportedError(message.message);
   }
 
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index ce387d5..df9dbd4 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -81,6 +81,9 @@
   bool get supportsExplicitGetterCalls => false;
 
   @override
+  bool get supportsNewMethodInvocationEncoding => false;
+
+  @override
   List<String> get extraRequiredLibraries => _requiredLibraries[name];
 
   @override
diff --git a/pkg/dartdev/lib/src/commands/fix.dart b/pkg/dartdev/lib/src/commands/fix.dart
index 9e5e3b5..975c2c7 100644
--- a/pkg/dartdev/lib/src/commands/fix.dart
+++ b/pkg/dartdev/lib/src/commands/fix.dart
@@ -88,10 +88,12 @@
     if (!dir.existsSync()) {
       usageException("Directory doesn't exist: ${dir.path}");
     }
+    dir = io.Directory(path.canonicalize(path.normalize(dir.absolute.path)));
+    var dirPath = dir.path;
 
     var modeText = dryRun ? ' (dry run)' : '';
 
-    final projectName = path.basename(path.canonicalize(dir.path));
+    final projectName = path.basename(dirPath);
     var progress = log.progress(
         'Computing fixes in ${log.ansi.emphasized(projectName)}$modeText');
 
@@ -111,7 +113,7 @@
       }
     });
 
-    fixes = await server.requestBulkFixes(dir.absolute.path);
+    fixes = await server.requestBulkFixes(dirPath);
     final List<SourceFileEdit> edits = fixes.edits;
 
     await server.shutdown();
@@ -119,16 +121,16 @@
     progress.finish(showTiming: true);
 
     if (testMode) {
-      if (_compareFixes(edits)) {
-        return 1;
-      }
+      var result = _compareFixesInDirectory(dir, edits);
+      log.stdout('Passed: ${result.passCount}, Failed: ${result.failCount}');
+      return result.failCount > 0 ? 1 : 0;
     } else if (edits.isEmpty) {
       log.stdout('Nothing to fix!');
     } else {
       var details = fixes.details;
       details.sort((f1, f2) => path
-          .relative(f1.path, from: dir.path)
-          .compareTo(path.relative(f2.path, from: dir.path)));
+          .relative(f1.path, from: dirPath)
+          .compareTo(path.relative(f2.path, from: dirPath)));
 
       var fileCount = 0;
       var fixCount = 0;
@@ -170,32 +172,83 @@
 
   /// Return `true` if any of the fixes fail to create the same content as is
   /// found in the golden file.
-  bool _compareFixes(List<SourceFileEdit> edits) {
-    var passCount = 0;
-    var failCount = 0;
+  _TestResult _compareFixesInDirectory(
+      io.Directory directory, List<SourceFileEdit> edits) {
+    var result = _TestResult();
+    //
+    // Gather the files of interest in this directory and process
+    // subdirectories.
+    //
+    var dartFiles = <io.File>[];
+    var expectFileMap = <String, io.File>{};
+    for (var child in directory.listSync()) {
+      if (child is io.Directory) {
+        var childResult = _compareFixesInDirectory(child, edits);
+        result.passCount += childResult.passCount;
+        result.failCount += childResult.failCount;
+      } else if (child is io.File) {
+        var name = child.name;
+        if (name.endsWith('.dart')) {
+          dartFiles.add(child);
+        } else if (name.endsWith('.expect')) {
+          expectFileMap[child.path] = child;
+        }
+      }
+    }
+    var editMap = <String, SourceFileEdit>{};
     for (var edit in edits) {
-      var filePath = edit.file;
+      editMap[edit.file] = edit;
+    }
+    for (var originalFile in dartFiles) {
+      var filePath = originalFile.path;
       var baseName = path.basename(filePath);
       var expectFileName = baseName + '.expect';
       var expectFilePath = path.join(path.dirname(filePath), expectFileName);
+      var expectFile = expectFileMap.remove(expectFilePath);
+      if (expectFile == null) {
+        result.failCount++;
+        log.stdout(
+            'No corresponding expect file for the Dart file at "$filePath".');
+        continue;
+      }
+      var edit = editMap[filePath];
       try {
-        var originalCode = io.File(filePath).readAsStringSync();
-        var expectedCode = io.File(expectFilePath).readAsStringSync();
-        var actualCode = SourceEdit.applySequence(originalCode, edit.edits);
-        if (actualCode != expectedCode) {
-          failCount++;
+        var originalCode = originalFile.readAsStringSync();
+        var expectedCode = expectFile.readAsStringSync();
+        var actualCode = edit == null
+            ? originalCode
+            : SourceEdit.applySequence(originalCode, edit.edits);
+        // Use a whitespace insensitive comparison.
+        if (_compressWhitespace(actualCode) !=
+            _compressWhitespace(expectedCode)) {
+          result.failCount++;
           _reportFailure(filePath, actualCode, expectedCode);
+          _printEdits(edits);
         } else {
-          passCount++;
+          result.passCount++;
         }
       } on io.FileSystemException {
-        // Ignored for now.
+        result.failCount++;
+        log.stdout('Failed to process "$filePath".');
+        log.stdout(
+            '  Ensure that the file and its expect file are both readable.');
       }
     }
-    log.stdout('Passed: $passCount, Failed: $failCount');
-    return failCount > 0;
+    //
+    // Report any `.expect` files that have no corresponding `.dart` file.
+    //
+    for (var unmatchedExpectPath in expectFileMap.keys) {
+      result.failCount++;
+      log.stdout(
+          'No corresponding Dart file for the expect file at "$unmatchedExpectPath".');
+    }
+    return result;
   }
 
+  /// Compress sequences of whitespace characters into a single space.
+  String _compressWhitespace(String code) =>
+      code.replaceAll(RegExp(r'\s*'), ' ');
+
   String _pluralFix(int count) => count == 1 ? 'fix' : 'fixes';
 
   void _printDetails(List<BulkFix> details, io.Directory workingDir) {
@@ -215,6 +268,16 @@
     }
   }
 
+  void _printEdits(List<SourceFileEdit> edits) {
+    log.stdout('Edits returned from server:');
+    for (var fileEdit in edits) {
+      log.stdout('  ${fileEdit.file}');
+      for (var edit in fileEdit.edits) {
+        log.stdout("    ${edit.offset} - ${edit.end}, '${edit.replacement}'");
+      }
+    }
+  }
+
   /// Report that the [actualCode] produced by applying fixes to the content of
   /// [filePath] did not match the [expectedCode].
   void _reportFailure(String filePath, String actualCode, String expectedCode) {
@@ -228,3 +291,15 @@
 
   static String _format(int value) => _numberFormat.format(value);
 }
+
+/// The result of running tests in a given directory.
+class _TestResult {
+  /// The number of tests that passed.
+  int passCount = 0;
+
+  /// The number of tests that failed.
+  int failCount = 0;
+
+  /// Initialize a newly created result object.
+  _TestResult();
+}
diff --git a/pkg/dartdev/test/commands/fix_test.dart b/pkg/dartdev/test/commands/fix_test.dart
index 74ff1e4..b3d2940 100644
--- a/pkg/dartdev/test/commands/fix_test.dart
+++ b/pkg/dartdev/test/commands/fix_test.dart
@@ -21,12 +21,38 @@
 void defineFix() {
   TestProject p;
 
+  ProcessResult result;
+
   final bullet = Logger.standard().ansi.bullet;
 
   setUp(() => p = null);
 
   tearDown(() => p?.dispose());
 
+  void assertResult({int exitCode = 0}) {
+    String message;
+    if (result.exitCode != exitCode) {
+      if (result.stderr.isNotEmpty) {
+        message = 'Error code was ${result.exitCode} and stderr was not empty';
+      } else {
+        message = 'Error code was ${result.exitCode}';
+      }
+    } else if (result.stderr.isNotEmpty) {
+      message = 'stderr was not empty';
+    } else {
+      return;
+    }
+    fail('''
+$message
+
+stdout:
+${result.stdout}
+
+stderr:
+${result.stderr}
+''');
+  }
+
   ProcessResult runFix(List<String> args, {String workingDir}) {
     if (runFromSource) {
       var binary = path.join(Directory.current.path, 'bin', 'dartdev.dart');
@@ -188,7 +214,7 @@
   });
 
   group('compare-to-golden', () {
-    test('different', () {
+    test('applied fixes do not match expected', () {
       p = project(
         mainSrc: '''
 class A {
@@ -215,12 +241,11 @@
   String a() => '';
 }
 ''');
-      var result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
-      expect(result.exitCode, 1);
-      expect(result.stderr, isEmpty);
+      result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
+      assertResult(exitCode: 1);
     });
 
-    test('same', () {
+    test('applied fixes match expected', () {
       p = project(
         mainSrc: '''
 class A {
@@ -248,9 +273,66 @@
   String a() => '';
 }
 ''');
-      var result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
-      expect(result.exitCode, 0);
-      expect(result.stderr, isEmpty);
+      result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
+      assertResult();
+    });
+
+    test('missing expect', () {
+      p = project(
+        mainSrc: '''
+class A {
+  String a() => "";
+}
+
+class B extends A {
+  String a() => "";
+}
+''',
+        analysisOptions: '''
+linter:
+  rules:
+    - annotate_overrides
+    - prefer_single_quotes
+''',
+      );
+      result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
+      assertResult(exitCode: 1);
+    });
+
+    test('missing original', () {
+      p = project(mainSrc: '''
+class C {}
+''');
+      p.file('lib/main.dart.expect', '''
+class C {}
+''');
+      p.file('lib/secondary.dart.expect', '''
+class A {}
+''');
+      result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
+      assertResult(exitCode: 1);
+    });
+
+    test('no fixes to apply does not match expected', () {
+      p = project(
+        mainSrc: '''
+class A {
+  String a() => "";
+}
+''',
+        analysisOptions: '''
+linter:
+  rules:
+    - annotate_overrides
+''',
+      );
+      p.file('lib/main.dart.expect', '''
+class A {
+  String a() => '';
+}
+''');
+      result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
+      assertResult(exitCode: 1);
     });
   });
 }
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index ba707e4..0aa4cce 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -4354,12 +4354,40 @@
           .toAssignExpression(_emitVariableRef(node.variable));
 
   @override
+  js_ast.Expression visitDynamicGet(DynamicGet node) {
+    return _emitPropertyGet(node.receiver, null, node.name.name);
+  }
+
+  @override
+  js_ast.Expression visitInstanceGet(InstanceGet node) {
+    return _emitPropertyGet(
+        node.receiver, node.interfaceTarget, node.name.name);
+  }
+
+  @override
+  js_ast.Expression visitInstanceTearOff(InstanceTearOff node) {
+    return _emitPropertyGet(
+        node.receiver, node.interfaceTarget, node.name.name);
+  }
+
+  @override
   js_ast.Expression visitPropertyGet(PropertyGet node) {
     return _emitPropertyGet(
         node.receiver, node.interfaceTarget, node.name.text);
   }
 
   @override
+  js_ast.Expression visitDynamicSet(DynamicSet node) {
+    return _emitPropertySet(node.receiver, null, node.value, node.name.text);
+  }
+
+  @override
+  js_ast.Expression visitInstanceSet(InstanceSet node) {
+    return _emitPropertySet(
+        node.receiver, node.interfaceTarget, node.value, node.name.text);
+  }
+
+  @override
   js_ast.Expression visitPropertySet(PropertySet node) {
     return _emitPropertySet(
         node.receiver, node.interfaceTarget, node.value, node.name.text);
@@ -4469,6 +4497,10 @@
   js_ast.Expression visitStaticGet(StaticGet node) =>
       _emitStaticGet(node.target);
 
+  @override
+  js_ast.Expression visitStaticTearOff(StaticTearOff node) =>
+      _emitStaticGet(node.target);
+
   js_ast.Expression _emitStaticGet(Member target) {
     var result = _emitStaticTarget(target);
     if (_reifyTearoff(target)) {
@@ -4492,6 +4524,43 @@
   }
 
   @override
+  js_ast.Expression visitDynamicInvocation(DynamicInvocation node) {
+    return _emitMethodCall(node.receiver, null, node.arguments, node);
+  }
+
+  @override
+  js_ast.Expression visitFunctionInvocation(FunctionInvocation node) {
+    return _emitMethodCall(node.receiver, null, node.arguments, node);
+  }
+
+  @override
+  js_ast.Expression visitInstanceInvocation(InstanceInvocation node) {
+    return _emitMethodCall(
+        node.receiver, node.interfaceTarget, node.arguments, node);
+  }
+
+  @override
+  js_ast.Expression visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+    return _emitMethodCall(
+        VariableGet(node.variable)..fileOffset = node.fileOffset,
+        null,
+        node.arguments,
+        node);
+  }
+
+  @override
+  js_ast.Expression visitEqualsCall(EqualsCall node) {
+    return _emitEqualityOperator(node.left, node.interfaceTarget, node.right,
+        negated: node.isNot);
+  }
+
+  @override
+  js_ast.Expression visitEqualsNull(EqualsNull node) {
+    return _emitCoreIdenticalCall([node.expression, NullLiteral()],
+        negated: node.isNot);
+  }
+
+  @override
   js_ast.Expression visitMethodInvocation(MethodInvocation node) {
     return _emitMethodCall(
         node.receiver, node.interfaceTarget, node.arguments, node);
@@ -4680,16 +4749,29 @@
     // If the consumer of the expression is '==' or '!=' with a constant that
     // fits in 31 bits, adding a coercion does not change the result of the
     // comparison, e.g.  `a & ~b == 0`.
+    Expression left;
+    Expression right;
+    String op;
     if (parent is InvocationExpression &&
         parent.arguments.positional.length == 1) {
-      var op = parent.name.text;
-      var left = getInvocationReceiver(parent);
-      var right = parent.arguments.positional[0];
-      if (left != null && op == '==') {
+      op = parent.name.text;
+      left = getInvocationReceiver(parent);
+      right = parent.arguments.positional[0];
+    } else if (parent is EqualsCall) {
+      left = parent.left;
+      right = parent.right;
+      op = '==';
+    } else if (parent is EqualsNull) {
+      left = parent.expression;
+      right = NullLiteral();
+      op = '==';
+    }
+    if (left != null) {
+      if (op == '==') {
         const MAX = 0x7fffffff;
         if (_asIntInRange(right, 0, MAX) != null) return uncoerced;
         if (_asIntInRange(left, 0, MAX) != null) return uncoerced;
-      } else if (left != null && op == '>>') {
+      } else if (op == '>>') {
         if (_isDefinitelyNonNegative(left) &&
             _asIntInRange(right, 0, 31) != null) {
           // Parent will generate `# >>> n`.
@@ -6071,6 +6153,11 @@
   @override
   js_ast.Expression visitUnevaluatedConstant(UnevaluatedConstant node) =>
       throw UnsupportedError('Encountered an unevaluated constant: $node');
+
+  @override
+  js_ast.Expression visitFunctionTearOff(FunctionTearOff node) {
+    return _emitPropertyGet(node.receiver, null, 'call');
+  }
 }
 
 bool _isInlineJSFunction(Statement body) {
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
index eb746a7..20253e5 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
@@ -40,7 +40,7 @@
         Visitor;
 
 DiagnosticMessage _createInternalError(Uri uri, int line, int col, String msg) {
-  return Message(Code<String>('Expression Compiler Internal error', null),
+  return Message(Code<String>('Expression Compiler Internal error'),
           message: msg)
       .withLocation(uri, 0, 0)
       .withFormatting(
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 437fcce..fbc740a 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -190,8 +190,20 @@
   return result;
 }
 
-Expression getInvocationReceiver(InvocationExpression node) =>
-    node is MethodInvocation ? node.receiver : null;
+Expression getInvocationReceiver(InvocationExpression node) {
+  if (node is MethodInvocation) {
+    return node.receiver;
+  } else if (node is InstanceInvocation) {
+    return node.receiver;
+  } else if (node is DynamicInvocation) {
+    return node.receiver;
+  } else if (node is FunctionInvocation) {
+    return node.receiver;
+  } else if (node is LocalFunctionInvocation) {
+    return VariableGet(node.variable);
+  }
+  return null;
+}
 
 bool isInlineJS(Member e) =>
     e is Procedure &&
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index c8fdf12..bd952b2 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -95,9 +95,30 @@
       _getterIsNullable(node.interfaceTarget, node);
 
   @override
+  bool visitInstanceGet(InstanceGet node) =>
+      _getterIsNullable(node.interfaceTarget, node);
+
+  @override
+  bool visitDynamicGet(DynamicGet node) => _getterIsNullable(null, node);
+
+  @override
+  bool visitInstanceTearOff(InstanceTearOff node) =>
+      _getterIsNullable(node.interfaceTarget, node);
+
+  @override
+  bool visitFunctionTearOff(FunctionTearOff node) =>
+      _getterIsNullable(null, node);
+
+  @override
   bool visitPropertySet(PropertySet node) => isNullable(node.value);
 
   @override
+  bool visitInstanceSet(InstanceSet node) => isNullable(node.value);
+
+  @override
+  bool visitDynamicSet(DynamicSet node) => isNullable(node.value);
+
+  @override
   bool visitSuperPropertyGet(SuperPropertyGet node) =>
       _getterIsNullable(node.interfaceTarget, node);
 
@@ -108,6 +129,10 @@
   bool visitStaticGet(StaticGet node) => _getterIsNullable(node.target, node);
 
   @override
+  bool visitStaticTearOff(StaticTearOff node) =>
+      _getterIsNullable(node.target, node);
+
+  @override
   bool visitStaticSet(StaticSet node) => isNullable(node.value);
 
   @override
@@ -115,6 +140,29 @@
       node.interfaceTarget, node.name.text, node, node.receiver);
 
   @override
+  bool visitInstanceInvocation(InstanceInvocation node) =>
+      _invocationIsNullable(
+          node.interfaceTarget, node.name.text, node, node.receiver);
+
+  @override
+  bool visitDynamicInvocation(DynamicInvocation node) =>
+      _invocationIsNullable(null, node.name.text, node, node.receiver);
+
+  @override
+  bool visitFunctionInvocation(FunctionInvocation node) =>
+      _invocationIsNullable(null, 'call', node, node.receiver);
+
+  @override
+  bool visitLocalFunctionInvocation(LocalFunctionInvocation node) =>
+      _invocationIsNullable(null, 'call', node, VariableGet(node.variable));
+
+  @override
+  bool visitEqualsNull(EqualsNull node) => false;
+
+  @override
+  bool visitEqualsCall(EqualsCall node) => false;
+
+  @override
   bool visitSuperMethodInvocation(SuperMethodInvocation node) =>
       _invocationIsNullable(node.interfaceTarget, node.name.text, node);
 
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index d22ded9..ca82d2e 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -48,6 +48,9 @@
   bool get supportsExplicitGetterCalls => false;
 
   @override
+  bool get supportsNewMethodInvocationEncoding => true;
+
+  @override
   String get name => 'dartdevc';
 
   @override
@@ -400,14 +403,44 @@
   }
 
   @override
+  void visitInstanceGet(InstanceGet node) {
+    _checkTearoff(node.interfaceTarget);
+    super.visitInstanceGet(node);
+  }
+
+  @override
   void visitPropertySet(PropertySet node) {
     _checkTarget(node.receiver, node.interfaceTarget);
     super.visitPropertySet(node);
   }
 
   @override
+  void visitInstanceSet(InstanceSet node) {
+    _checkTarget(node.receiver, node.interfaceTarget);
+    super.visitInstanceSet(node);
+  }
+
+  @override
   void visitMethodInvocation(MethodInvocation node) {
     _checkTarget(node.receiver, node.interfaceTarget);
     super.visitMethodInvocation(node);
   }
+
+  @override
+  void visitInstanceInvocation(InstanceInvocation node) {
+    _checkTarget(node.receiver, node.interfaceTarget);
+    super.visitInstanceInvocation(node);
+  }
+
+  @override
+  void visitInstanceTearOff(InstanceTearOff node) {
+    _checkTearoff(node.interfaceTarget);
+    super.visitInstanceTearOff(node);
+  }
+
+  @override
+  void visitEqualsCall(EqualsCall node) {
+    _checkTarget(node.left, node.interfaceTarget);
+    super.visitEqualsCall(node);
+  }
 }
diff --git a/pkg/dev_compiler/test/nullable_inference_test.dart b/pkg/dev_compiler/test/nullable_inference_test.dart
index 9753c50..e077906 100644
--- a/pkg/dev_compiler/test/nullable_inference_test.dart
+++ b/pkg/dev_compiler/test/nullable_inference_test.dart
@@ -310,7 +310,7 @@
         var y = (x = null) == null;
         print(x);
         print(y);
-      }''', '1, (x = null).{dart.core::Object.==}(null), y');
+      }''', '1, (x = null) == null, y');
     });
     test('declaration from variable transitive', () async {
       await expectNotNull('''main() {
@@ -369,6 +369,7 @@
           var z = 1;
           print(z);
         }
+        f;
         f(42);
       }''', '0, void () => dart.core::print("g"), "g", g, y, 1, z, f, 42');
     });
@@ -378,6 +379,7 @@
         f(x) {
           y = x;
         }
+        f;
         f(42);
         print(y);
       }''', '0, f, 42');
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index e0970d7..f6c6267 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -47,6 +47,7 @@
         messageFfiExpectedConstant,
         noLength,
         templateFfiDartTypeMismatch,
+        templateFfiEmptyStruct,
         templateFfiExpectedExceptionalReturn,
         templateFfiExpectedNoExceptionalReturn,
         templateFfiExtendsOrImplementsSealedClass,
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 833753c..113198e 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -286,7 +286,11 @@
       internalProblem(
           messageInternalProblemAlreadyInitialized, charOffset, fileUri);
     }
-    _fieldEncoding.createBodies(coreTypes, initializer);
+    _fieldEncoding.createBodies(
+        coreTypes,
+        initializer,
+        library
+            .loader.target.backendTarget.supportsNewMethodInvocationEncoding);
   }
 
   @override
@@ -526,7 +530,8 @@
   ///
   /// This method is not called for fields in outlines unless their are constant
   /// or part of a const constructor.
-  void createBodies(CoreTypes coreTypes, Expression initializer);
+  void createBodies(CoreTypes coreTypes, Expression initializer,
+      bool useNewMethodInvocationEncoding);
 
   List<Initializer> createInitializer(int fileOffset, Expression value,
       {bool isSynthetic});
@@ -605,7 +610,8 @@
   void completeSignature(CoreTypes coreTypes) {}
 
   @override
-  void createBodies(CoreTypes coreTypes, Expression initializer) {
+  void createBodies(CoreTypes coreTypes, Expression initializer,
+      bool useNewMethodInvocationEncoding) {
     if (initializer != null) {
       _field.initializer = initializer..parent = _field;
     }
@@ -854,7 +860,8 @@
   }
 
   @override
-  void createBodies(CoreTypes coreTypes, Expression initializer) {
+  void createBodies(CoreTypes coreTypes, Expression initializer,
+      bool useNewMethodInvocationEncoding) {
     assert(_type != null, "Type has not been computed for field $name.");
     if (isSetEncoding == late_lowering.IsSetEncoding.useSentinel) {
       _field.initializer = new StaticInvocation(coreTypes.createSentinelMethod,
@@ -870,11 +877,15 @@
         ..fileOffset = fileOffset
         ..parent = _lateIsSetField;
     }
-    _lateGetter.function.body = _createGetterBody(coreTypes, name, initializer)
+    _lateGetter.function.body = _createGetterBody(
+        coreTypes, name, initializer, useNewMethodInvocationEncoding)
       ..parent = _lateGetter.function;
     if (_lateSetter != null) {
       _lateSetter.function.body = _createSetterBody(
-          coreTypes, name, _lateSetter.function.positionalParameters.first)
+          coreTypes,
+          name,
+          _lateSetter.function.positionalParameters.first,
+          useNewMethodInvocationEncoding)
         ..parent = _lateSetter.function;
     }
   }
@@ -936,8 +947,8 @@
     }
   }
 
-  Statement _createGetterBody(
-      CoreTypes coreTypes, String name, Expression initializer);
+  Statement _createGetterBody(CoreTypes coreTypes, String name,
+      Expression initializer, bool useNewMethodInvocationEncoding);
 
   Procedure _createSetter(
       String name, Uri fileUri, int charOffset, Procedure referenceFrom,
@@ -960,8 +971,8 @@
       ..isNonNullableByDefault = true;
   }
 
-  Statement _createSetterBody(
-      CoreTypes coreTypes, String name, VariableDeclaration parameter);
+  Statement _createSetterBody(CoreTypes coreTypes, String name,
+      VariableDeclaration parameter, bool useNewMethodInvocationEncoding);
 
   @override
   DartType get type => _type;
@@ -1165,8 +1176,8 @@
 
 mixin NonFinalLate on AbstractLateFieldEncoding {
   @override
-  Statement _createSetterBody(
-      CoreTypes coreTypes, String name, VariableDeclaration parameter) {
+  Statement _createSetterBody(CoreTypes coreTypes, String name,
+      VariableDeclaration parameter, bool useNewMethodInvocationEncoding) {
     assert(_type != null, "Type has not been computed for field $name.");
     return late_lowering.createSetterBody(
         coreTypes, fileOffset, name, parameter, _type,
@@ -1181,11 +1192,11 @@
 
 mixin LateWithoutInitializer on AbstractLateFieldEncoding {
   @override
-  Statement _createGetterBody(
-      CoreTypes coreTypes, String name, Expression initializer) {
+  Statement _createGetterBody(CoreTypes coreTypes, String name,
+      Expression initializer, bool useNewMethodInvocationEncoding) {
     assert(_type != null, "Type has not been computed for field $name.");
     return late_lowering.createGetterBodyWithoutInitializer(
-        coreTypes, fileOffset, name, type,
+        coreTypes, fileOffset, name, type, useNewMethodInvocationEncoding,
         createVariableRead: _createFieldRead,
         createIsSetRead: () => _createFieldGet(_lateIsSetField),
         isSetEncoding: isSetEncoding,
@@ -1245,11 +1256,11 @@
             isSetStrategy);
 
   @override
-  Statement _createGetterBody(
-      CoreTypes coreTypes, String name, Expression initializer) {
+  Statement _createGetterBody(CoreTypes coreTypes, String name,
+      Expression initializer, bool useNewMethodInvocationEncoding) {
     assert(_type != null, "Type has not been computed for field $name.");
-    return late_lowering.createGetterWithInitializer(
-        coreTypes, fileOffset, name, _type, initializer,
+    return late_lowering.createGetterWithInitializer(coreTypes, fileOffset,
+        name, _type, initializer, useNewMethodInvocationEncoding,
         createVariableRead: _createFieldRead,
         createVariableWrite: (Expression value) =>
             _createFieldSet(_field, value),
@@ -1286,11 +1297,11 @@
             isSetStrategy);
 
   @override
-  Statement _createSetterBody(
-      CoreTypes coreTypes, String name, VariableDeclaration parameter) {
+  Statement _createSetterBody(CoreTypes coreTypes, String name,
+      VariableDeclaration parameter, bool useNewMethodInvocationEncoding) {
     assert(_type != null, "Type has not been computed for field $name.");
-    return late_lowering.createSetterBodyFinal(
-        coreTypes, fileOffset, name, parameter, type,
+    return late_lowering.createSetterBodyFinal(coreTypes, fileOffset, name,
+        parameter, type, useNewMethodInvocationEncoding,
         shouldReturnValue: false,
         createVariableRead: () => _createFieldGet(_field),
         createVariableWrite: (Expression value) =>
@@ -1327,11 +1338,11 @@
             isCovariant,
             isSetStrategy);
   @override
-  Statement _createGetterBody(
-      CoreTypes coreTypes, String name, Expression initializer) {
+  Statement _createGetterBody(CoreTypes coreTypes, String name,
+      Expression initializer, bool useNewMethodInvocationEncoding) {
     assert(_type != null, "Type has not been computed for field $name.");
-    return late_lowering.createGetterWithInitializerWithRecheck(
-        coreTypes, fileOffset, name, _type, initializer,
+    return late_lowering.createGetterWithInitializerWithRecheck(coreTypes,
+        fileOffset, name, _type, initializer, useNewMethodInvocationEncoding,
         createVariableRead: _createFieldRead,
         createVariableWrite: (Expression value) =>
             _createFieldSet(_field, value),
@@ -1349,8 +1360,8 @@
       null;
 
   @override
-  Statement _createSetterBody(
-          CoreTypes coreTypes, String name, VariableDeclaration parameter) =>
+  Statement _createSetterBody(CoreTypes coreTypes, String name,
+          VariableDeclaration parameter, bool useNewMethodInvocationEncoding) =>
       null;
 }
 
@@ -1571,7 +1582,8 @@
   void completeSignature(CoreTypes coreTypes) {}
 
   @override
-  void createBodies(CoreTypes coreTypes, Expression initializer) {
+  void createBodies(CoreTypes coreTypes, Expression initializer,
+      bool useNewMethodInvocationEncoding) {
     //assert(initializer != null);
   }
 
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
index f7adca0..7e29218 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
@@ -32,7 +32,6 @@
         bool isNonNullableByDefault)> codeAmbiguousExtensionMethod = const Code<
     Message Function(String name, DartType _type, bool isNonNullableByDefault)>(
   "AmbiguousExtensionMethod",
-  templateAmbiguousExtensionMethod,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -72,7 +71,6 @@
         Message Function(
             String name, DartType _type, bool isNonNullableByDefault)>(
   "AmbiguousExtensionOperator",
-  templateAmbiguousExtensionOperator,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -112,7 +110,6 @@
         Message Function(
             String name, DartType _type, bool isNonNullableByDefault)>(
   "AmbiguousExtensionProperty",
-  templateAmbiguousExtensionProperty,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -148,8 +145,7 @@
             bool isNonNullableByDefault)> codeAmbiguousSupertypes =
     const Code<
             Message Function(String name, DartType _type, DartType _type2,
-                bool isNonNullableByDefault)>(
-        "AmbiguousSupertypes", templateAmbiguousSupertypes,
+                bool isNonNullableByDefault)>("AmbiguousSupertypes",
         analyzerCodes: <String>["AMBIGUOUS_SUPERTYPES"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -186,7 +182,7 @@
     codeArgumentTypeNotAssignable = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "ArgumentTypeNotAssignable", templateArgumentTypeNotAssignable,
+        "ArgumentTypeNotAssignable",
         analyzerCodes: <String>["ARGUMENT_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -223,7 +219,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "ArgumentTypeNotAssignableNullability",
-        templateArgumentTypeNotAssignableNullability,
         analyzerCodes: <String>["ARGUMENT_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -254,7 +249,6 @@
     codeArgumentTypeNotAssignableNullabilityNull =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
         "ArgumentTypeNotAssignableNullabilityNull",
-        templateArgumentTypeNotAssignableNullabilityNull,
         analyzerCodes: <String>["ARGUMENT_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -290,7 +284,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "ArgumentTypeNotAssignableNullabilityNullType",
-        templateArgumentTypeNotAssignableNullabilityNullType,
         analyzerCodes: <String>["ARGUMENT_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -327,7 +320,6 @@
             Message Function(DartType _type, DartType _type2, DartType _type3,
                 DartType _type4, bool isNonNullableByDefault)>(
         "ArgumentTypeNotAssignablePartNullability",
-        templateArgumentTypeNotAssignablePartNullability,
         analyzerCodes: <String>["ARGUMENT_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -372,7 +364,6 @@
     codeConstEvalCaseImplementsEqual = const Code<
         Message Function(Constant _constant, bool isNonNullableByDefault)>(
   "ConstEvalCaseImplementsEqual",
-  templateConstEvalCaseImplementsEqual,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -401,7 +392,7 @@
 const Code<Message Function(Constant _constant, bool isNonNullableByDefault)>
     codeConstEvalDuplicateElement = const Code<
             Message Function(Constant _constant, bool isNonNullableByDefault)>(
-        "ConstEvalDuplicateElement", templateConstEvalDuplicateElement,
+        "ConstEvalDuplicateElement",
         analyzerCodes: <String>["EQUAL_ELEMENTS_IN_CONST_SET"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -430,7 +421,7 @@
 const Code<Message Function(Constant _constant, bool isNonNullableByDefault)>
     codeConstEvalDuplicateKey = const Code<
             Message Function(Constant _constant, bool isNonNullableByDefault)>(
-        "ConstEvalDuplicateKey", templateConstEvalDuplicateKey,
+        "ConstEvalDuplicateKey",
         analyzerCodes: <String>["EQUAL_KEYS_IN_CONST_MAP"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -460,7 +451,6 @@
     codeConstEvalElementImplementsEqual = const Code<
             Message Function(Constant _constant, bool isNonNullableByDefault)>(
         "ConstEvalElementImplementsEqual",
-        templateConstEvalElementImplementsEqual,
         analyzerCodes: <String>["CONST_SET_ELEMENT_TYPE_IMPLEMENTS_EQUALS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -489,7 +479,6 @@
     codeConstEvalFreeTypeParameter =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "ConstEvalFreeTypeParameter",
-  templateConstEvalFreeTypeParameter,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -524,7 +513,6 @@
         Message Function(String stringOKEmpty, Constant _constant,
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "ConstEvalInvalidBinaryOperandType",
-  templateConstEvalInvalidBinaryOperandType,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -534,6 +522,7 @@
     DartType _type,
     DartType _type2,
     bool isNonNullableByDefault) {
+  // ignore: unnecessary_null_comparison
   if (stringOKEmpty == null || stringOKEmpty.isEmpty) stringOKEmpty = '(empty)';
   TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
   List<Object> constantParts = labeler.labelConstant(_constant);
@@ -573,7 +562,6 @@
         Message Function(
             Constant _constant, DartType _type, bool isNonNullableByDefault)>(
   "ConstEvalInvalidEqualsOperandType",
-  templateConstEvalInvalidEqualsOperandType,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -610,12 +598,12 @@
             Message Function(String stringOKEmpty, Constant _constant,
                 bool isNonNullableByDefault)>(
         "ConstEvalInvalidMethodInvocation",
-        templateConstEvalInvalidMethodInvocation,
         analyzerCodes: <String>["UNDEFINED_OPERATOR"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsConstEvalInvalidMethodInvocation(
     String stringOKEmpty, Constant _constant, bool isNonNullableByDefault) {
+  // ignore: unnecessary_null_comparison
   if (stringOKEmpty == null || stringOKEmpty.isEmpty) stringOKEmpty = '(empty)';
   TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
   List<Object> constantParts = labeler.labelConstant(_constant);
@@ -644,13 +632,13 @@
             bool isNonNullableByDefault)> codeConstEvalInvalidPropertyGet =
     const Code<
             Message Function(String stringOKEmpty, Constant _constant,
-                bool isNonNullableByDefault)>(
-        "ConstEvalInvalidPropertyGet", templateConstEvalInvalidPropertyGet,
+                bool isNonNullableByDefault)>("ConstEvalInvalidPropertyGet",
         analyzerCodes: <String>["CONST_EVAL_THROWS_EXCEPTION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsConstEvalInvalidPropertyGet(
     String stringOKEmpty, Constant _constant, bool isNonNullableByDefault) {
+  // ignore: unnecessary_null_comparison
   if (stringOKEmpty == null || stringOKEmpty.isEmpty) stringOKEmpty = '(empty)';
   TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
   List<Object> constantParts = labeler.labelConstant(_constant);
@@ -678,7 +666,6 @@
     codeConstEvalInvalidStringInterpolationOperand = const Code<
             Message Function(Constant _constant, bool isNonNullableByDefault)>(
         "ConstEvalInvalidStringInterpolationOperand",
-        templateConstEvalInvalidStringInterpolationOperand,
         analyzerCodes: <String>["CONST_EVAL_TYPE_BOOL_NUM_STRING"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -708,7 +695,7 @@
 const Code<Message Function(Constant _constant, bool isNonNullableByDefault)>
     codeConstEvalInvalidSymbolName = const Code<
             Message Function(Constant _constant, bool isNonNullableByDefault)>(
-        "ConstEvalInvalidSymbolName", templateConstEvalInvalidSymbolName,
+        "ConstEvalInvalidSymbolName",
         analyzerCodes: <String>["CONST_EVAL_THROWS_EXCEPTION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -745,7 +732,6 @@
     Message Function(Constant _constant, DartType _type, DartType _type2,
         bool isNonNullableByDefault)>(
   "ConstEvalInvalidType",
-  templateConstEvalInvalidType,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -778,7 +764,7 @@
 const Code<Message Function(Constant _constant, bool isNonNullableByDefault)>
     codeConstEvalKeyImplementsEqual = const Code<
             Message Function(Constant _constant, bool isNonNullableByDefault)>(
-        "ConstEvalKeyImplementsEqual", templateConstEvalKeyImplementsEqual,
+        "ConstEvalKeyImplementsEqual",
         analyzerCodes: <String>[
       "CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS"
     ]);
@@ -818,7 +804,7 @@
     codeDeferredTypeAnnotation = const Code<
             Message Function(
                 DartType _type, String name, bool isNonNullableByDefault)>(
-        "DeferredTypeAnnotation", templateDeferredTypeAnnotation,
+        "DeferredTypeAnnotation",
         analyzerCodes: <String>["TYPE_ANNOTATION_DEFERRED_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -855,7 +841,6 @@
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "FfiDartTypeMismatch",
-  templateFfiDartTypeMismatch,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -885,7 +870,6 @@
     codeFfiExpectedExceptionalReturn =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "FfiExpectedExceptionalReturn",
-  templateFfiExpectedExceptionalReturn,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -914,7 +898,6 @@
     codeFfiExpectedNoExceptionalReturn =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "FfiExpectedNoExceptionalReturn",
-  templateFfiExpectedNoExceptionalReturn,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -946,7 +929,6 @@
     codeFfiTypeInvalid =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "FfiTypeInvalid",
-  templateFfiTypeInvalid,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -983,7 +965,6 @@
     Message Function(DartType _type, DartType _type2, DartType _type3,
         bool isNonNullableByDefault)>(
   "FfiTypeMismatch",
-  templateFfiTypeMismatch,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1023,7 +1004,6 @@
         Message Function(
             String name, DartType _type, bool isNonNullableByDefault)>(
   "FieldNonNullableNotInitializedByConstructorError",
-  templateFieldNonNullableNotInitializedByConstructorError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1060,7 +1040,6 @@
         Message Function(
             String name, DartType _type, bool isNonNullableByDefault)>(
   "FieldNonNullableWithoutInitializerError",
-  templateFieldNonNullableWithoutInitializerError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1098,7 +1077,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "ForInLoopElementTypeNotAssignable",
-        templateForInLoopElementTypeNotAssignable,
         analyzerCodes: <String>["FOR_IN_OF_INVALID_ELEMENT_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1138,7 +1116,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "ForInLoopElementTypeNotAssignableNullability",
-        templateForInLoopElementTypeNotAssignableNullability,
         analyzerCodes: <String>["FOR_IN_OF_INVALID_ELEMENT_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1178,7 +1155,6 @@
             Message Function(DartType _type, DartType _type2, DartType _type3,
                 DartType _type4, bool isNonNullableByDefault)>(
         "ForInLoopElementTypeNotAssignablePartNullability",
-        templateForInLoopElementTypeNotAssignablePartNullability,
         analyzerCodes: <String>["FOR_IN_OF_INVALID_ELEMENT_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1228,7 +1204,7 @@
     codeForInLoopTypeNotIterable = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "ForInLoopTypeNotIterable", templateForInLoopTypeNotIterable,
+        "ForInLoopTypeNotIterable",
         analyzerCodes: <String>["FOR_IN_OF_INVALID_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1265,7 +1241,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "ForInLoopTypeNotIterableNullability",
-        templateForInLoopTypeNotIterableNullability,
         analyzerCodes: <String>["FOR_IN_OF_INVALID_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1302,7 +1277,6 @@
             Message Function(DartType _type, DartType _type2, DartType _type3,
                 DartType _type4, bool isNonNullableByDefault)>(
         "ForInLoopTypeNotIterablePartNullability",
-        templateForInLoopTypeNotIterablePartNullability,
         analyzerCodes: <String>["FOR_IN_OF_INVALID_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1349,7 +1323,6 @@
     codeGenericFunctionTypeInferredAsActualTypeArgument =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
         "GenericFunctionTypeInferredAsActualTypeArgument",
-        templateGenericFunctionTypeInferredAsActualTypeArgument,
         analyzerCodes: <String>["GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1380,7 +1353,7 @@
 const Code<Message Function(DartType _type, bool isNonNullableByDefault)>
     codeImplicitCallOfNonMethod =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
-        "ImplicitCallOfNonMethod", templateImplicitCallOfNonMethod,
+        "ImplicitCallOfNonMethod",
         analyzerCodes: <String>["IMPLICIT_CALL_OF_NON_METHOD"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1413,7 +1386,6 @@
     codeImplicitReturnNull =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "ImplicitReturnNull",
-  templateImplicitReturnNull,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1448,7 +1420,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "IncompatibleRedirecteeFunctionType",
-        templateIncompatibleRedirecteeFunctionType,
         analyzerCodes: <String>["REDIRECT_TO_INVALID_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1484,9 +1455,12 @@
         Message Function(DartType _type, DartType _type2, String name,
             String name2, bool isNonNullableByDefault)>
     codeIncorrectTypeArgument = const Code<
-            Message Function(DartType _type, DartType _type2, String name,
-                String name2, bool isNonNullableByDefault)>(
-        "IncorrectTypeArgument", templateIncorrectTypeArgument,
+            Message Function(
+                DartType _type,
+                DartType _type2,
+                String name,
+                String name2,
+                bool isNonNullableByDefault)>("IncorrectTypeArgument",
         analyzerCodes: <String>["TYPE_ARGUMENT_NOT_MATCHING_BOUNDS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1535,7 +1509,6 @@
             Message Function(DartType _type, DartType _type2, String name,
                 String name2, bool isNonNullableByDefault)>(
         "IncorrectTypeArgumentInReturnType",
-        templateIncorrectTypeArgumentInReturnType,
         analyzerCodes: <String>["TYPE_ARGUMENT_NOT_MATCHING_BOUNDS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1607,7 +1580,7 @@
                 String name3,
                 String name4,
                 bool isNonNullableByDefault)>(
-        "IncorrectTypeArgumentInSupertype", templateIncorrectTypeArgumentInSupertype,
+        "IncorrectTypeArgumentInSupertype",
         analyzerCodes: <String>["TYPE_ARGUMENT_NOT_MATCHING_BOUNDS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1692,7 +1665,7 @@
                 String name3,
                 String name4,
                 bool isNonNullableByDefault)>(
-        "IncorrectTypeArgumentInSupertypeInferred", templateIncorrectTypeArgumentInSupertypeInferred,
+        "IncorrectTypeArgumentInSupertypeInferred",
         analyzerCodes: <String>["TYPE_ARGUMENT_NOT_MATCHING_BOUNDS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1751,9 +1724,12 @@
         Message Function(DartType _type, DartType _type2, String name,
             String name2, bool isNonNullableByDefault)>
     codeIncorrectTypeArgumentInferred = const Code<
-            Message Function(DartType _type, DartType _type2, String name,
-                String name2, bool isNonNullableByDefault)>(
-        "IncorrectTypeArgumentInferred", templateIncorrectTypeArgumentInferred,
+            Message Function(
+                DartType _type,
+                DartType _type2,
+                String name,
+                String name2,
+                bool isNonNullableByDefault)>("IncorrectTypeArgumentInferred",
         analyzerCodes: <String>["TYPE_ARGUMENT_NOT_MATCHING_BOUNDS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1799,10 +1775,13 @@
         Message Function(DartType _type, DartType _type2, String name,
             DartType _type3, String name2, bool isNonNullableByDefault)>
     codeIncorrectTypeArgumentQualified = const Code<
-            Message Function(DartType _type, DartType _type2, String name,
-                DartType _type3, String name2, bool isNonNullableByDefault)>(
-        "IncorrectTypeArgumentQualified",
-        templateIncorrectTypeArgumentQualified,
+            Message Function(
+                DartType _type,
+                DartType _type2,
+                String name,
+                DartType _type3,
+                String name2,
+                bool isNonNullableByDefault)>("IncorrectTypeArgumentQualified",
         analyzerCodes: <String>["TYPE_ARGUMENT_NOT_MATCHING_BOUNDS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1858,7 +1837,7 @@
     codeIncorrectTypeArgumentQualifiedInferred = const Code<
             Message Function(DartType _type, DartType _type2, String name,
                 DartType _type3, String name2, bool isNonNullableByDefault)>(
-        "IncorrectTypeArgumentQualifiedInferred", templateIncorrectTypeArgumentQualifiedInferred,
+        "IncorrectTypeArgumentQualifiedInferred",
         analyzerCodes: <String>["TYPE_ARGUMENT_NOT_MATCHING_BOUNDS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1914,7 +1893,6 @@
     const Code<
             Message Function(String name, DartType _type, DartType _type2,
                 bool isNonNullableByDefault)>("InitializingFormalTypeMismatch",
-        templateInitializingFormalTypeMismatch,
         analyzerCodes: <String>["INVALID_PARAMETER_DECLARATION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1954,7 +1932,6 @@
             Message Function(
                 String string, DartType _type, bool isNonNullableByDefault)>(
         "InternalProblemUnsupportedNullability",
-        templateInternalProblemUnsupportedNullability,
         severity: Severity.internalProblem);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1989,7 +1966,7 @@
     codeInvalidAssignmentError = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "InvalidAssignmentError", templateInvalidAssignmentError,
+        "InvalidAssignmentError",
         analyzerCodes: <String>["INVALID_ASSIGNMENT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2026,7 +2003,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "InvalidAssignmentErrorNullability",
-        templateInvalidAssignmentErrorNullability,
         analyzerCodes: <String>["INVALID_ASSIGNMENT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2057,7 +2033,6 @@
     codeInvalidAssignmentErrorNullabilityNull =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
         "InvalidAssignmentErrorNullabilityNull",
-        templateInvalidAssignmentErrorNullabilityNull,
         analyzerCodes: <String>["INVALID_ASSIGNMENT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2092,7 +2067,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "InvalidAssignmentErrorNullabilityNullType",
-        templateInvalidAssignmentErrorNullabilityNullType,
         analyzerCodes: <String>["INVALID_ASSIGNMENT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2129,7 +2103,6 @@
             Message Function(DartType _type, DartType _type2, DartType _type3,
                 DartType _type4, bool isNonNullableByDefault)>(
         "InvalidAssignmentErrorPartNullability",
-        templateInvalidAssignmentErrorPartNullability,
         analyzerCodes: <String>["INVALID_ASSIGNMENT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2182,7 +2155,7 @@
     codeInvalidCastFunctionExpr = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "InvalidCastFunctionExpr", templateInvalidCastFunctionExpr,
+        "InvalidCastFunctionExpr",
         analyzerCodes: <String>["INVALID_CAST_FUNCTION_EXPR"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2226,7 +2199,7 @@
     codeInvalidCastLiteralList = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "InvalidCastLiteralList", templateInvalidCastLiteralList,
+        "InvalidCastLiteralList",
         analyzerCodes: <String>["INVALID_CAST_LITERAL_LIST"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2270,7 +2243,7 @@
     codeInvalidCastLiteralMap = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "InvalidCastLiteralMap", templateInvalidCastLiteralMap,
+        "InvalidCastLiteralMap",
         analyzerCodes: <String>["INVALID_CAST_LITERAL_MAP"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2314,7 +2287,7 @@
     codeInvalidCastLiteralSet = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "InvalidCastLiteralSet", templateInvalidCastLiteralSet,
+        "InvalidCastLiteralSet",
         analyzerCodes: <String>["INVALID_CAST_LITERAL_SET"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2358,7 +2331,7 @@
     codeInvalidCastLocalFunction = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "InvalidCastLocalFunction", templateInvalidCastLocalFunction,
+        "InvalidCastLocalFunction",
         analyzerCodes: <String>["INVALID_CAST_FUNCTION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2402,7 +2375,7 @@
     codeInvalidCastNewExpr = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "InvalidCastNewExpr", templateInvalidCastNewExpr,
+        "InvalidCastNewExpr",
         analyzerCodes: <String>["INVALID_CAST_NEW_EXPR"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2443,7 +2416,7 @@
     codeInvalidCastStaticMethod = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "InvalidCastStaticMethod", templateInvalidCastStaticMethod,
+        "InvalidCastStaticMethod",
         analyzerCodes: <String>["INVALID_CAST_METHOD"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2482,7 +2455,7 @@
     codeInvalidCastTopLevelFunction = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "InvalidCastTopLevelFunction", templateInvalidCastTopLevelFunction,
+        "InvalidCastTopLevelFunction",
         analyzerCodes: <String>["INVALID_CAST_FUNCTION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2519,7 +2492,6 @@
     Message Function(DartType _type, String name, DartType _type2, String name2,
         bool isNonNullableByDefault)>(
   "InvalidGetterSetterType",
-  templateInvalidGetterSetterType,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2565,7 +2537,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeBothInheritedField",
-  templateInvalidGetterSetterTypeBothInheritedField,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2612,7 +2583,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeBothInheritedFieldLegacy",
-  templateInvalidGetterSetterTypeBothInheritedFieldLegacy,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2663,7 +2633,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeBothInheritedGetter",
-  templateInvalidGetterSetterTypeBothInheritedGetter,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2710,7 +2679,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeBothInheritedGetterLegacy",
-  templateInvalidGetterSetterTypeBothInheritedGetterLegacy,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2760,7 +2728,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeFieldInherited",
-  templateInvalidGetterSetterTypeFieldInherited,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2807,7 +2774,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeFieldInheritedLegacy",
-  templateInvalidGetterSetterTypeFieldInheritedLegacy,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2857,7 +2823,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeGetterInherited",
-  templateInvalidGetterSetterTypeGetterInherited,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2904,7 +2869,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeGetterInheritedLegacy",
-  templateInvalidGetterSetterTypeGetterInheritedLegacy,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2954,7 +2918,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeLegacy",
-  templateInvalidGetterSetterTypeLegacy,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3001,7 +2964,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeSetterInheritedField",
-  templateInvalidGetterSetterTypeSetterInheritedField,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3052,7 +3014,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeSetterInheritedFieldLegacy",
-  templateInvalidGetterSetterTypeSetterInheritedFieldLegacy,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3103,7 +3064,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeSetterInheritedGetter",
-  templateInvalidGetterSetterTypeSetterInheritedGetter,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3154,7 +3114,6 @@
         Message Function(DartType _type, String name, DartType _type2,
             String name2, bool isNonNullableByDefault)>(
   "InvalidGetterSetterTypeSetterInheritedGetterLegacy",
-  templateInvalidGetterSetterTypeSetterInheritedGetterLegacy,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3206,7 +3165,6 @@
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "InvalidReturn",
-  templateInvalidReturn,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3245,7 +3203,6 @@
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "InvalidReturnAsync",
-  templateInvalidReturnAsync,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3282,7 +3239,6 @@
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "InvalidReturnAsyncNullability",
-  templateInvalidReturnAsyncNullability,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3313,7 +3269,6 @@
     codeInvalidReturnAsyncNullabilityNull =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "InvalidReturnAsyncNullabilityNull",
-  templateInvalidReturnAsyncNullabilityNull,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3348,7 +3303,6 @@
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "InvalidReturnAsyncNullabilityNullType",
-  templateInvalidReturnAsyncNullabilityNullType,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3385,7 +3339,6 @@
         Message Function(DartType _type, DartType _type2, DartType _type3,
             DartType _type4, bool isNonNullableByDefault)>(
   "InvalidReturnAsyncPartNullability",
-  templateInvalidReturnAsyncPartNullability,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3435,7 +3388,6 @@
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "InvalidReturnNullability",
-  templateInvalidReturnNullability,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3466,7 +3418,6 @@
     codeInvalidReturnNullabilityNull =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "InvalidReturnNullabilityNull",
-  templateInvalidReturnNullabilityNull,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3501,7 +3452,6 @@
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "InvalidReturnNullabilityNullType",
-  templateInvalidReturnNullabilityNullType,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3538,7 +3488,6 @@
         Message Function(DartType _type, DartType _type2, DartType _type3,
             DartType _type4, bool isNonNullableByDefault)>(
   "InvalidReturnPartNullability",
-  templateInvalidReturnPartNullability,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3588,7 +3537,6 @@
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "MainWrongParameterType",
-  templateMainWrongParameterType,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3625,7 +3573,6 @@
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "MainWrongParameterTypeExported",
-  templateMainWrongParameterTypeExported,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3662,7 +3609,6 @@
             Message Function(DartType _type, DartType _type2, DartType _type3,
                 bool isNonNullableByDefault)>(
         "MixinApplicationIncompatibleSupertype",
-        templateMixinApplicationIncompatibleSupertype,
         analyzerCodes: <String>["MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3700,8 +3646,7 @@
             bool isNonNullableByDefault)> codeMixinInferenceNoMatchingClass =
     const Code<
             Message Function(String name, String name2, DartType _type,
-                bool isNonNullableByDefault)>(
-        "MixinInferenceNoMatchingClass", templateMixinInferenceNoMatchingClass,
+                bool isNonNullableByDefault)>("MixinInferenceNoMatchingClass",
         analyzerCodes: <String>["MIXIN_INFERENCE_NO_POSSIBLE_SUBSTITUTION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3733,7 +3678,6 @@
     codeNonNullAwareSpreadIsNull =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "NonNullAwareSpreadIsNull",
-  templateNonNullAwareSpreadIsNull,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3766,7 +3710,7 @@
     codeNonNullableInNullAware = const Code<
             Message Function(
                 String name, DartType _type, bool isNonNullableByDefault)>(
-        "NonNullableInNullAware", templateNonNullableInNullAware,
+        "NonNullableInNullAware",
         severity: Severity.warning);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3798,7 +3742,6 @@
     codeNullableExpressionCallError =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "NullableExpressionCallError",
-  templateNullableExpressionCallError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3833,7 +3776,6 @@
         bool isNonNullableByDefault)> codeNullableMethodCallError = const Code<
     Message Function(String name, DartType _type, bool isNonNullableByDefault)>(
   "NullableMethodCallError",
-  templateNullableMethodCallError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3871,7 +3813,6 @@
         Message Function(
             String name, DartType _type, bool isNonNullableByDefault)>(
   "NullableOperatorCallError",
-  templateNullableOperatorCallError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3909,7 +3850,6 @@
         Message Function(
             String name, DartType _type, bool isNonNullableByDefault)>(
   "NullablePropertyAccessError",
-  templateNullablePropertyAccessError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3950,7 +3890,6 @@
             Message Function(
                 String name, DartType _type, bool isNonNullableByDefault)>(
         "OptionalNonNullableWithoutInitializerError",
-        templateOptionalNonNullableWithoutInitializerError,
         analyzerCodes: <String>["MISSING_DEFAULT_VALUE_FOR_PARAMETER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3987,9 +3926,13 @@
         Message Function(String name, String name2, DartType _type,
             DartType _type2, String name3, bool isNonNullableByDefault)>
     codeOverrideTypeMismatchParameter = const Code<
-            Message Function(String name, String name2, DartType _type,
-                DartType _type2, String name3, bool isNonNullableByDefault)>(
-        "OverrideTypeMismatchParameter", templateOverrideTypeMismatchParameter,
+            Message Function(
+                String name,
+                String name2,
+                DartType _type,
+                DartType _type2,
+                String name3,
+                bool isNonNullableByDefault)>("OverrideTypeMismatchParameter",
         analyzerCodes: <String>["INVALID_METHOD_OVERRIDE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4042,10 +3985,12 @@
         Message Function(String name, DartType _type, DartType _type2,
             String name2, bool isNonNullableByDefault)>
     codeOverrideTypeMismatchReturnType = const Code<
-            Message Function(String name, DartType _type, DartType _type2,
-                String name2, bool isNonNullableByDefault)>(
-        "OverrideTypeMismatchReturnType",
-        templateOverrideTypeMismatchReturnType,
+            Message Function(
+                String name,
+                DartType _type,
+                DartType _type2,
+                String name2,
+                bool isNonNullableByDefault)>("OverrideTypeMismatchReturnType",
         analyzerCodes: <String>["INVALID_METHOD_OVERRIDE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4093,9 +4038,12 @@
         Message Function(String name, DartType _type, DartType _type2,
             String name2, bool isNonNullableByDefault)>
     codeOverrideTypeMismatchSetter = const Code<
-            Message Function(String name, DartType _type, DartType _type2,
-                String name2, bool isNonNullableByDefault)>(
-        "OverrideTypeMismatchSetter", templateOverrideTypeMismatchSetter,
+            Message Function(
+                String name,
+                DartType _type,
+                DartType _type2,
+                String name2,
+                bool isNonNullableByDefault)>("OverrideTypeMismatchSetter",
         analyzerCodes: <String>["INVALID_METHOD_OVERRIDE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4141,7 +4089,6 @@
         Message Function(DartType _type, String name, String name2,
             DartType _type2, String name3, bool isNonNullableByDefault)>(
   "OverrideTypeVariablesBoundMismatch",
-  templateOverrideTypeVariablesBoundMismatch,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4196,7 +4143,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "RedirectingFactoryIncompatibleTypeArgument",
-        templateRedirectingFactoryIncompatibleTypeArgument,
         analyzerCodes: <String>["TYPE_ARGUMENT_NOT_MATCHING_BOUNDS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4232,7 +4178,7 @@
     codeSpreadElementTypeMismatch = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "SpreadElementTypeMismatch", templateSpreadElementTypeMismatch,
+        "SpreadElementTypeMismatch",
         analyzerCodes: <String>["LIST_ELEMENT_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4269,7 +4215,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "SpreadElementTypeMismatchNullability",
-        templateSpreadElementTypeMismatchNullability,
         analyzerCodes: <String>["LIST_ELEMENT_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4306,7 +4251,6 @@
             Message Function(DartType _type, DartType _type2, DartType _type3,
                 DartType _type4, bool isNonNullableByDefault)>(
         "SpreadElementTypeMismatchPartNullability",
-        templateSpreadElementTypeMismatchPartNullability,
         analyzerCodes: <String>["LIST_ELEMENT_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4356,7 +4300,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "SpreadMapEntryElementKeyTypeMismatch",
-        templateSpreadMapEntryElementKeyTypeMismatch,
         analyzerCodes: <String>["MAP_KEY_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4394,7 +4337,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "SpreadMapEntryElementKeyTypeMismatchNullability",
-        templateSpreadMapEntryElementKeyTypeMismatchNullability,
         analyzerCodes: <String>["MAP_KEY_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4433,7 +4375,6 @@
             Message Function(DartType _type, DartType _type2, DartType _type3,
                 DartType _type4, bool isNonNullableByDefault)>(
         "SpreadMapEntryElementKeyTypeMismatchPartNullability",
-        templateSpreadMapEntryElementKeyTypeMismatchPartNullability,
         analyzerCodes: <String>["MAP_KEY_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4483,7 +4424,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "SpreadMapEntryElementValueTypeMismatch",
-        templateSpreadMapEntryElementValueTypeMismatch,
         analyzerCodes: <String>["MAP_VALUE_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4521,7 +4461,6 @@
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
         "SpreadMapEntryElementValueTypeMismatchNullability",
-        templateSpreadMapEntryElementValueTypeMismatchNullability,
         analyzerCodes: <String>["MAP_VALUE_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4560,7 +4499,6 @@
             Message Function(DartType _type, DartType _type2, DartType _type3,
                 DartType _type4, bool isNonNullableByDefault)>(
         "SpreadMapEntryElementValueTypeMismatchPartNullability",
-        templateSpreadMapEntryElementValueTypeMismatchPartNullability,
         analyzerCodes: <String>["MAP_VALUE_TYPE_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4604,7 +4542,6 @@
     codeSpreadMapEntryTypeMismatch =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "SpreadMapEntryTypeMismatch",
-  templateSpreadMapEntryTypeMismatch,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4636,7 +4573,6 @@
     codeSpreadTypeMismatch =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "SpreadTypeMismatch",
-  templateSpreadTypeMismatch,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4670,7 +4606,7 @@
     codeSwitchExpressionNotAssignable = const Code<
             Message Function(
                 DartType _type, DartType _type2, bool isNonNullableByDefault)>(
-        "SwitchExpressionNotAssignable", templateSwitchExpressionNotAssignable,
+        "SwitchExpressionNotAssignable",
         analyzerCodes: <String>["SWITCH_EXPRESSION_NOT_ASSIGNABLE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4707,7 +4643,6 @@
         Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>(
   "SwitchExpressionNotSubtype",
-  templateSwitchExpressionNotSubtype,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4738,7 +4673,6 @@
     codeThrowingNotAssignableToObjectError =
     const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
   "ThrowingNotAssignableToObjectError",
-  templateThrowingNotAssignableToObjectError,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4776,7 +4710,7 @@
     codeUndefinedGetter = const Code<
             Message Function(
                 String name, DartType _type, bool isNonNullableByDefault)>(
-        "UndefinedGetter", templateUndefinedGetter,
+        "UndefinedGetter",
         analyzerCodes: <String>["UNDEFINED_GETTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4818,7 +4752,7 @@
     codeUndefinedMethod = const Code<
             Message Function(
                 String name, DartType _type, bool isNonNullableByDefault)>(
-        "UndefinedMethod", templateUndefinedMethod,
+        "UndefinedMethod",
         analyzerCodes: <String>["UNDEFINED_METHOD"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4860,7 +4794,7 @@
     codeUndefinedOperator = const Code<
             Message Function(
                 String name, DartType _type, bool isNonNullableByDefault)>(
-        "UndefinedOperator", templateUndefinedOperator,
+        "UndefinedOperator",
         analyzerCodes: <String>["UNDEFINED_METHOD"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4902,7 +4836,7 @@
     codeUndefinedSetter = const Code<
             Message Function(
                 String name, DartType _type, bool isNonNullableByDefault)>(
-        "UndefinedSetter", templateUndefinedSetter,
+        "UndefinedSetter",
         analyzerCodes: <String>["UNDEFINED_SETTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index a92f302..9ca9572 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -570,6 +570,27 @@
         constantEvaluator.evaluate(_staticTypeContext, node), node);
   }
 
+  bool _isNull(Expression node) {
+    return node is NullLiteral ||
+        node is ConstantExpression && node.constant is NullConstant;
+  }
+
+  @override
+  Expression visitEqualsCall(EqualsCall node) {
+    Expression left = node.left.accept<TreeNode>(this);
+    Expression right = node.right.accept<TreeNode>(this);
+    if (_isNull(left)) {
+      return new EqualsNull(right, isNot: node.isNot)
+        ..fileOffset = node.fileOffset;
+    } else if (_isNull(right)) {
+      return new EqualsNull(left, isNot: node.isNot)
+        ..fileOffset = node.fileOffset;
+    }
+    node.left = left..parent = node;
+    node.right = right..parent = node;
+    return node;
+  }
+
   @override
   Expression visitStaticGet(StaticGet node) {
     final Member target = node.target;
@@ -591,6 +612,15 @@
   }
 
   @override
+  Expression visitStaticTearOff(StaticTearOff node) {
+    final Member target = node.target;
+    if (target is Procedure && target.kind == ProcedureKind.Method) {
+      return evaluateAndTransformWithContext(node, node);
+    }
+    return super.visitStaticTearOff(node);
+  }
+
+  @override
   SwitchCase visitSwitchCase(SwitchCase node) {
     transformExpressions(node.expressions, node);
     return super.visitSwitchCase(node);
@@ -1741,12 +1771,19 @@
   }
 
   @override
-  Constant visitMethodInvocation(MethodInvocation node) {
-    // We have no support for generic method invocation atm.
-    if (node.arguments.named.isNotEmpty) {
+  Constant visitDynamicInvocation(DynamicInvocation node) {
+    // We have no support for generic method invocation at the moment.
+    if (node.arguments.types.isNotEmpty) {
       return createInvalidExpressionConstant(node, "generic method invocation");
     }
 
+    // We have no support for method invocation with named arguments at the
+    // moment.
+    if (node.arguments.named.isNotEmpty) {
+      return createInvalidExpressionConstant(
+          node, "method invocation with named arguments");
+    }
+
     final Constant receiver = _evaluateSubexpression(node.receiver);
     if (receiver is AbortConstant) return receiver;
     final List<Constant> arguments =
@@ -1763,35 +1800,139 @@
     if (shouldBeUnevaluated) {
       return unevaluated(
           node,
-          new MethodInvocation(extract(receiver), node.name,
+          new DynamicInvocation(node.kind, extract(receiver), node.name,
               unevaluatedArguments(arguments, {}, node.arguments.types))
+            ..fileOffset = node.fileOffset);
+    }
+
+    return _handleInvocation(node, node.name, receiver, arguments);
+  }
+
+  @override
+  Constant visitInstanceInvocation(InstanceInvocation node) {
+    // We have no support for generic method invocation at the moment.
+    if (node.arguments.types.isNotEmpty) {
+      return createInvalidExpressionConstant(node, "generic method invocation");
+    }
+
+    // We have no support for method invocation with named arguments at the
+    // moment.
+    if (node.arguments.named.isNotEmpty) {
+      return createInvalidExpressionConstant(
+          node, "method invocation with named arguments");
+    }
+
+    final Constant receiver = _evaluateSubexpression(node.receiver);
+    if (receiver is AbortConstant) return receiver;
+    final List<Constant> arguments =
+        _evaluatePositionalArguments(node.arguments);
+
+    if (arguments == null && _gotError != null) {
+      AbortConstant error = _gotError;
+      _gotError = null;
+      return error;
+    }
+    assert(_gotError == null);
+    assert(arguments != null);
+
+    if (shouldBeUnevaluated) {
+      return unevaluated(
+          node,
+          new InstanceInvocation(node.kind, extract(receiver), node.name,
+              unevaluatedArguments(arguments, {}, node.arguments.types),
+              functionType: node.functionType,
+              interfaceTarget: node.interfaceTarget)
             ..fileOffset = node.fileOffset
             ..flags = node.flags);
     }
 
-    final String op = node.name.text;
+    return _handleInvocation(node, node.name, receiver, arguments);
+  }
+
+  @override
+  Constant visitFunctionInvocation(FunctionInvocation node) {
+    return createInvalidExpressionConstant(node, "function invocation");
+  }
+
+  @override
+  Constant visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+    return createInvalidExpressionConstant(node, "local function invocation");
+  }
+
+  @override
+  Constant visitEqualsCall(EqualsCall node) {
+    final Constant left = _evaluateSubexpression(node.left);
+    if (left is AbortConstant) return left;
+    final Constant right = _evaluateSubexpression(node.right);
+    if (right is AbortConstant) return right;
+
+    if (shouldBeUnevaluated) {
+      return unevaluated(
+          node,
+          new EqualsCall(extract(left), extract(right),
+              isNot: node.isNot,
+              functionType: node.functionType,
+              interfaceTarget: node.interfaceTarget)
+            ..fileOffset = node.fileOffset);
+    }
+
+    return _handleEquals(node, left, right, isNot: node.isNot);
+  }
+
+  @override
+  Constant visitEqualsNull(EqualsNull node) {
+    final Constant expression = _evaluateSubexpression(node.expression);
+    if (expression is AbortConstant) return expression;
+
+    if (shouldBeUnevaluated) {
+      return unevaluated(
+          node,
+          new EqualsNull(extract(expression), isNot: node.isNot)
+            ..fileOffset = node.fileOffset);
+    }
+
+    return _handleEquals(node, expression, nullConstant, isNot: node.isNot);
+  }
+
+  Constant _handleEquals(Expression node, Constant left, Constant right,
+      {bool isNot}) {
+    assert(isNot != null);
+    if (left is NullConstant ||
+        left is BoolConstant ||
+        left is IntConstant ||
+        left is DoubleConstant ||
+        left is StringConstant ||
+        right is NullConstant) {
+      // [DoubleConstant] uses [identical] to determine equality, so we need
+      // to take the special cases into account.
+      Constant result =
+          doubleSpecialCases(left, right) ?? makeBoolConstant(left == right);
+      if (isNot) {
+        if (result == trueConstant) {
+          result = falseConstant;
+        } else {
+          assert(result == falseConstant);
+          result = trueConstant;
+        }
+      }
+      return result;
+    } else {
+      return createErrorConstant(
+          node,
+          templateConstEvalInvalidEqualsOperandType.withArguments(
+              left, left.getType(_staticTypeContext), isNonNullableByDefault));
+    }
+  }
+
+  Constant _handleInvocation(
+      Expression node, Name name, Constant receiver, List<Constant> arguments) {
+    final String op = name.text;
 
     // Handle == and != first (it's common between all types). Since `a != b` is
     // parsed as `!(a == b)` it is handled implicitly through ==.
     if (arguments.length == 1 && op == '==') {
       final Constant right = arguments[0];
-
-      if (receiver is NullConstant ||
-          receiver is BoolConstant ||
-          receiver is IntConstant ||
-          receiver is DoubleConstant ||
-          receiver is StringConstant ||
-          right is NullConstant) {
-        // [DoubleConstant] uses [identical] to determine equality, so we need
-        // to take the special cases into account.
-        return doubleSpecialCases(receiver, right) ??
-            makeBoolConstant(receiver == right);
-      } else {
-        return createErrorConstant(
-            node,
-            templateConstEvalInvalidEqualsOperandType.withArguments(receiver,
-                receiver.getType(_staticTypeContext), isNonNullableByDefault));
-      }
+      return _handleEquals(node, receiver, right, isNot: false);
     }
 
     // This is a white-listed set of methods we need to support on constants.
@@ -1909,6 +2050,48 @@
   }
 
   @override
+  Constant visitMethodInvocation(MethodInvocation node) {
+    // We have no support for generic method invocation at the moment.
+    if (node.arguments.types.isNotEmpty) {
+      return createInvalidExpressionConstant(node, "generic method invocation");
+    }
+
+    // We have no support for method invocation with named arguments at the
+    // moment.
+    if (node.arguments.named.isNotEmpty) {
+      return createInvalidExpressionConstant(
+          node, "method invocation with named arguments");
+    }
+
+    final Constant receiver = _evaluateSubexpression(node.receiver);
+    if (receiver is AbortConstant) return receiver;
+    final List<Constant> arguments =
+        _evaluatePositionalArguments(node.arguments);
+
+    if (arguments == null && _gotError != null) {
+      AbortConstant error = _gotError;
+      _gotError = null;
+      return error;
+    }
+    assert(_gotError == null);
+    assert(arguments != null);
+
+    if (shouldBeUnevaluated) {
+      return unevaluated(
+          node,
+          new MethodInvocation(
+              extract(receiver),
+              node.name,
+              unevaluatedArguments(arguments, {}, node.arguments.types),
+              node.interfaceTarget)
+            ..fileOffset = node.fileOffset
+            ..flags = node.flags);
+    }
+
+    return _handleInvocation(node, node.name, receiver, arguments);
+  }
+
+  @override
   Constant visitLogicalExpression(LogicalExpression node) {
     final Constant left = _evaluateSubexpression(node.left);
     if (left is AbortConstant) return left;
@@ -2015,6 +2198,86 @@
   }
 
   @override
+  Constant visitInstanceGet(InstanceGet node) {
+    if (node.receiver is ThisExpression) {
+      // Probably unreachable unless trying to evaluate non-const stuff as
+      // const.
+      // Access "this" during instance creation.
+      if (instanceBuilder == null) {
+        return createErrorConstant(node, messageNotAConstantExpression);
+      }
+
+      for (final Field field in instanceBuilder.fields.keys) {
+        if (field.name == node.name) {
+          return instanceBuilder.fields[field];
+        }
+      }
+
+      // Meant as a "stable backstop for situations where Fasta fails to
+      // rewrite various erroneous constructs into invalid expressions".
+      // Probably unreachable.
+      return createInvalidExpressionConstant(node,
+          'Could not evaluate field get ${node.name} on incomplete instance');
+    }
+
+    final Constant receiver = _evaluateSubexpression(node.receiver);
+    if (receiver is AbortConstant) return receiver;
+    if (receiver is StringConstant && node.name.text == 'length') {
+      return canonicalize(intFolder.makeIntConstant(receiver.value.length));
+    } else if (shouldBeUnevaluated) {
+      return unevaluated(
+          node,
+          new InstanceGet(node.kind, extract(receiver), node.name,
+              resultType: node.resultType,
+              interfaceTarget: node.interfaceTarget));
+    } else if (receiver is NullConstant) {
+      return createErrorConstant(node, messageConstEvalNullValue);
+    }
+    return createErrorConstant(
+        node,
+        templateConstEvalInvalidPropertyGet.withArguments(
+            node.name.text, receiver, isNonNullableByDefault));
+  }
+
+  @override
+  Constant visitDynamicGet(DynamicGet node) {
+    final Constant receiver = _evaluateSubexpression(node.receiver);
+    if (receiver is AbortConstant) return receiver;
+    if (receiver is StringConstant && node.name.text == 'length') {
+      return canonicalize(intFolder.makeIntConstant(receiver.value.length));
+    } else if (shouldBeUnevaluated) {
+      return unevaluated(
+          node, new DynamicGet(node.kind, extract(receiver), node.name));
+    } else if (receiver is NullConstant) {
+      return createErrorConstant(node, messageConstEvalNullValue);
+    }
+    return createErrorConstant(
+        node,
+        templateConstEvalInvalidPropertyGet.withArguments(
+            node.name.text, receiver, isNonNullableByDefault));
+  }
+
+  @override
+  Constant visitInstanceTearOff(InstanceTearOff node) {
+    final Constant receiver = _evaluateSubexpression(node.receiver);
+    if (receiver is AbortConstant) return receiver;
+    return createErrorConstant(
+        node,
+        templateConstEvalInvalidPropertyGet.withArguments(
+            node.name.text, receiver, isNonNullableByDefault));
+  }
+
+  @override
+  Constant visitFunctionTearOff(FunctionTearOff node) {
+    final Constant receiver = _evaluateSubexpression(node.receiver);
+    if (receiver is AbortConstant) return receiver;
+    return createErrorConstant(
+        node,
+        templateConstEvalInvalidPropertyGet.withArguments(
+            Name.callName.text, receiver, isNonNullableByDefault));
+  }
+
+  @override
   Constant visitPropertyGet(PropertyGet node) {
     if (node.receiver is ThisExpression) {
       // Probably unreachable unless trying to evaluate non-const stuff as
@@ -2132,6 +2395,25 @@
   }
 
   @override
+  Constant visitStaticTearOff(StaticTearOff node) {
+    return withNewEnvironment(() {
+      final Member target = node.target;
+      if (target is Procedure) {
+        if (target.kind == ProcedureKind.Method) {
+          return canonicalize(new TearOffConstant(target));
+        }
+        return createErrorConstant(
+            node,
+            templateConstEvalInvalidStaticInvocation
+                .withArguments(target.name.name));
+      } else {
+        return createInvalidExpressionConstant(
+            node, 'No support for ${target.runtimeType} in a static tear-off.');
+      }
+    });
+  }
+
+  @override
   Constant visitStringConcatenation(StringConcatenation node) {
     final List<Object> concatenated = <Object>[new StringBuffer()];
     for (int i = 0; i < node.expressions.length; i++) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_int_folder.dart b/pkg/front_end/lib/src/fasta/kernel/constant_int_folder.dart
index 0d73f92..84dfd13 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_int_folder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_int_folder.dart
@@ -34,17 +34,17 @@
   Constant makeIntConstant(int value, {bool unsigned: false});
 
   Constant foldUnaryOperator(
-      MethodInvocation node, String op, covariant Constant operand);
+      Expression node, String op, covariant Constant operand);
 
-  Constant foldBinaryOperator(MethodInvocation node, String op,
+  Constant foldBinaryOperator(Expression node, String op,
       covariant Constant left, covariant Constant right);
 
-  Constant truncatingDivide(MethodInvocation node, num left, num right);
+  Constant truncatingDivide(Expression node, num left, num right);
 
   /// Returns [null] on success and an error-"constant" on failure, as such the
   /// return value should be checked.
   AbortConstant _checkOperands(
-      MethodInvocation node, String op, num left, num right) {
+      Expression node, String op, num left, num right) {
     if ((op == '<<' || op == '>>' || op == '>>>') && right < 0) {
       return evaluator.createErrorConstant(node,
           templateConstEvalNegativeShift.withArguments(op, '$left', '$right'));
@@ -69,8 +69,7 @@
   }
 
   @override
-  Constant foldUnaryOperator(
-      MethodInvocation node, String op, IntConstant operand) {
+  Constant foldUnaryOperator(Expression node, String op, IntConstant operand) {
     switch (op) {
       case 'unary-':
         return new IntConstant(-operand.value);
@@ -85,7 +84,7 @@
 
   @override
   Constant foldBinaryOperator(
-      MethodInvocation node, String op, IntConstant left, IntConstant right) {
+      Expression node, String op, IntConstant left, IntConstant right) {
     int a = left.value;
     int b = right.value;
     AbortConstant error = _checkOperands(node, op, a, b);
@@ -133,7 +132,7 @@
   }
 
   @override
-  Constant truncatingDivide(MethodInvocation node, num left, num right) {
+  Constant truncatingDivide(Expression node, num left, num right) {
     try {
       return new IntConstant(left ~/ right);
     } catch (e) {
@@ -174,7 +173,7 @@
 
   @override
   Constant foldUnaryOperator(
-      MethodInvocation node, String op, DoubleConstant operand) {
+      Expression node, String op, DoubleConstant operand) {
     switch (op) {
       case 'unary-':
         return new DoubleConstant(-operand.value);
@@ -189,8 +188,8 @@
   }
 
   @override
-  Constant foldBinaryOperator(MethodInvocation node, String op,
-      DoubleConstant left, DoubleConstant right) {
+  Constant foldBinaryOperator(
+      Expression node, String op, DoubleConstant left, DoubleConstant right) {
     double a = left.value;
     double b = right.value;
     AbortConstant error = _checkOperands(node, op, a, b);
@@ -244,7 +243,7 @@
   }
 
   @override
-  Constant truncatingDivide(MethodInvocation node, num left, num right) {
+  Constant truncatingDivide(Expression node, num left, num right) {
     double division = (left / right);
     if (division.isNaN || division.isInfinite) {
       return evaluator.createErrorConstant(node,
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 76afeea..cbe6ba2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -1183,8 +1183,10 @@
     } else {
       VariableDeclaration variable =
           createVariable(left, lhsResult.inferredType);
-      MethodInvocation equalsNull = createEqualsNull(
-          left.fileOffset, createVariableGet(variable), equalsMember);
+      Expression equalsNull = inferrer.createEqualsNull(
+          lhsResult.expression.fileOffset,
+          createVariableGet(variable),
+          equalsMember);
       VariableGet variableGet = createVariableGet(variable);
       if (inferrer.library.isNonNullableByDefault &&
           !identical(nonNullableLhsType, originalLhsType)) {
@@ -2852,8 +2854,8 @@
       //
       //     let v1 = o in v1.a == null ? v1.a = b : null
       //
-      MethodInvocation equalsNull =
-          createEqualsNull(node.fileOffset, read, equalsMember);
+      Expression equalsNull =
+          inferrer.createEqualsNull(node.fileOffset, read, equalsMember);
       ConditionalExpression conditional = new ConditionalExpression(equalsNull,
           write, new NullLiteral()..fileOffset = node.fileOffset, inferredType)
         ..fileOffset = node.fileOffset;
@@ -2866,7 +2868,7 @@
       //     let v1 = o in let v2 = v1.a in v2 == null ? v1.a = b : v2
       //
       VariableDeclaration readVariable = createVariable(read, readType);
-      MethodInvocation equalsNull = createEqualsNull(
+      Expression equalsNull = inferrer.createEqualsNull(
           node.fileOffset, createVariableGet(readVariable), equalsMember);
       VariableGet variableGet = createVariableGet(readVariable);
       if (inferrer.library.isNonNullableByDefault &&
@@ -2918,8 +2920,8 @@
       //
       //     a == null ? a = b : null
       //
-      MethodInvocation equalsNull =
-          createEqualsNull(node.fileOffset, read, equalsMember);
+      Expression equalsNull =
+          inferrer.createEqualsNull(node.fileOffset, read, equalsMember);
       replacement = new ConditionalExpression(
           equalsNull,
           writeResult.expression,
@@ -2932,7 +2934,7 @@
       //      let v1 = a in v1 == null ? a = b : v1
       //
       VariableDeclaration readVariable = createVariable(read, readType);
-      MethodInvocation equalsNull = createEqualsNull(
+      Expression equalsNull = inferrer.createEqualsNull(
           node.fileOffset, createVariableGet(readVariable), equalsMember);
       VariableGet variableGet = createVariableGet(readVariable);
       if (inferrer.library.isNonNullableByDefault &&
@@ -2973,8 +2975,14 @@
 
     Expression index = inferrer.ensureAssignableResult(indexType, indexResult);
 
-    ExpressionInferenceResult replacement = _computeIndexGet(node.fileOffset,
-        receiver, receiverType, indexGetTarget, index, readCheckKind);
+    ExpressionInferenceResult replacement = _computeIndexGet(
+        node.fileOffset,
+        receiver,
+        receiverType,
+        indexGetTarget,
+        index,
+        indexType,
+        readCheckKind);
     return inferrer.createNullAwareExpressionInferenceResult(
         replacement.inferredType, replacement.expression, nullAwareGuards);
   }
@@ -3027,8 +3035,8 @@
     // the type of the value parameter.
     DartType inferredType = valueResult.inferredType;
 
-    Expression assignment = _computeIndexSet(
-        node.fileOffset, receiver, receiverType, indexSetTarget, index, value);
+    Expression assignment = _computeIndexSet(node.fileOffset, receiver,
+        receiverType, indexSetTarget, index, indexType, value, valueType);
 
     Expression replacement;
     if (node.forEffect) {
@@ -3086,7 +3094,7 @@
       assignment = inferrer.createMissingSuperIndexSet(node.fileOffset,
           createVariableGet(indexVariable), createVariableGet(valueVariable));
     } else {
-      assert(indexSetTarget.isInstanceMember);
+      assert(indexSetTarget.isInstanceMember || indexSetTarget.isObjectMember);
       inferrer.instrumentation?.record(
           inferrer.uriForInstrumentation,
           node.fileOffset,
@@ -3161,7 +3169,9 @@
         receiverType,
         target,
         createVariableGet(indexVariable),
-        createVariableGet(valueVariable));
+        indexType,
+        createVariableGet(valueVariable),
+        valueType);
 
     VariableDeclaration assignmentVariable =
         createVariable(assignment, const VoidType());
@@ -3226,8 +3236,14 @@
     readIndex = inferrer.ensureAssignable(
         readIndexType, indexResult.inferredType, readIndex);
 
-    ExpressionInferenceResult readResult = _computeIndexGet(node.readOffset,
-        readReceiver, receiverType, readTarget, readIndex, checkKind);
+    ExpressionInferenceResult readResult = _computeIndexGet(
+        node.readOffset,
+        readReceiver,
+        receiverType,
+        readTarget,
+        readIndex,
+        readIndexType,
+        checkKind);
     reportNonNullableInNullAwareWarningIfNeeded(
         readResult.inferredType, "??=", node.readOffset);
     Expression read = readResult.expression;
@@ -3260,8 +3276,15 @@
       value = createVariableGet(valueVariable);
     }
 
-    Expression write = _computeIndexSet(node.writeOffset, writeReceiver,
-        receiverType, writeTarget, writeIndex, value);
+    Expression write = _computeIndexSet(
+        node.writeOffset,
+        writeReceiver,
+        receiverType,
+        writeTarget,
+        writeIndex,
+        writeIndexType,
+        value,
+        valueType);
 
     Expression inner;
     if (node.forEffect) {
@@ -3278,8 +3301,8 @@
       //     let indexVariable = a in
       //         o[indexVariable] == null ? o.[]=(indexVariable, b) : null
       //
-      MethodInvocation equalsNull =
-          createEqualsNull(node.testOffset, read, equalsMember);
+      Expression equalsNull =
+          inferrer.createEqualsNull(node.testOffset, read, equalsMember);
       ConditionalExpression conditional = new ConditionalExpression(equalsNull,
           write, new NullLiteral()..fileOffset = node.testOffset, inferredType)
         ..fileOffset = node.testOffset;
@@ -3312,7 +3335,7 @@
       assert(valueVariable != null);
 
       VariableDeclaration readVariable = createVariable(read, readType);
-      MethodInvocation equalsNull = createEqualsNull(
+      Expression equalsNull = inferrer.createEqualsNull(
           node.testOffset, createVariableGet(readVariable), equalsMember);
       VariableDeclaration writeVariable =
           createVariable(write, const VoidType());
@@ -3387,7 +3410,7 @@
     if (readTarget.isMissing) {
       read = inferrer.createMissingSuperIndexGet(node.readOffset, readIndex);
     } else {
-      assert(readTarget.isInstanceMember);
+      assert(readTarget.isInstanceMember || readTarget.isObjectMember);
       inferrer.instrumentation?.record(
           inferrer.uriForInstrumentation,
           node.readOffset,
@@ -3428,7 +3451,7 @@
       write = inferrer.createMissingSuperIndexSet(
           node.writeOffset, writeIndex, value);
     } else {
-      assert(writeTarget.isInstanceMember);
+      assert(writeTarget.isInstanceMember || writeTarget.isObjectMember);
       inferrer.instrumentation?.record(
           inferrer.uriForInstrumentation,
           node.writeOffset,
@@ -3449,8 +3472,8 @@
       //     let v1 = a in
       //        super[v1] == null ? super.[]=(v1, b) : null
       //
-      MethodInvocation equalsNull =
-          createEqualsNull(node.testOffset, read, equalsMember);
+      Expression equalsNull =
+          inferrer.createEqualsNull(node.testOffset, read, equalsMember);
       ConditionalExpression conditional = new ConditionalExpression(equalsNull,
           write, new NullLiteral()..fileOffset = node.testOffset, inferredType)
         ..fileOffset = node.testOffset;
@@ -3469,7 +3492,7 @@
       assert(valueVariable != null);
 
       VariableDeclaration readVariable = createVariable(read, readType);
-      MethodInvocation equalsNull = createEqualsNull(
+      Expression equalsNull = inferrer.createEqualsNull(
           node.testOffset, createVariableGet(readVariable), equalsMember);
       VariableDeclaration writeVariable =
           createVariable(write, const VoidType());
@@ -3552,6 +3575,7 @@
         receiverType,
         readTarget,
         readIndex,
+        readIndexType,
         MethodContravarianceCheckKind.none);
     reportNonNullableInNullAwareWarningIfNeeded(
         readResult.inferredType, "??=", node.readOffset);
@@ -3585,8 +3609,15 @@
       value = createVariableGet(valueVariable);
     }
 
-    Expression write = _computeIndexSet(node.writeOffset, writeReceiver,
-        receiverType, writeTarget, writeIndex, value);
+    Expression write = _computeIndexSet(
+        node.writeOffset,
+        writeReceiver,
+        receiverType,
+        writeTarget,
+        writeIndex,
+        writeIndexType,
+        value,
+        valueType);
 
     Expression replacement;
     if (node.forEffect) {
@@ -3597,8 +3628,8 @@
       //        receiverVariable[indexVariable] == null
       //          ? receiverVariable.[]=(indexVariable, b) : null
       //
-      MethodInvocation equalsNull =
-          createEqualsNull(node.testOffset, read, equalsMember);
+      Expression equalsNull =
+          inferrer.createEqualsNull(node.testOffset, read, equalsMember);
       ConditionalExpression conditional = new ConditionalExpression(equalsNull,
           write, new NullLiteral()..fileOffset = node.testOffset, inferredType)
         ..fileOffset = node.testOffset;
@@ -3619,7 +3650,7 @@
       assert(valueVariable != null);
 
       VariableDeclaration readVariable = createVariable(read, readType);
-      MethodInvocation equalsNull = createEqualsNull(
+      Expression equalsNull = inferrer.createEqualsNull(
           node.testOffset, createVariableGet(readVariable), equalsMember);
       VariableDeclaration writeVariable =
           createVariable(write, const VoidType());
@@ -3645,6 +3676,11 @@
     return new ExpressionInferenceResult(inferredType, replacement);
   }
 
+  bool _isNull(Expression node) {
+    return node is NullLiteral ||
+        node is ConstantExpression && node.constant is NullConstant;
+  }
+
   /// Creates an equals expression of using [left] and [right] as operands.
   ///
   /// [fileOffset] is used as the file offset for created nodes. [leftType] is
@@ -3656,16 +3692,40 @@
       {bool isNot}) {
     assert(isNot != null);
     inferrer.flowAnalysis.equalityOp_rightBegin(left, leftType);
-    ObjectAccessTarget equalsTarget = inferrer.findInterfaceMember(
-        leftType, equalsName, fileOffset,
-        includeExtensionMethods: true);
-
     bool typeNeeded = !inferrer.isTopLevel;
+
+    Expression equals;
     ExpressionInferenceResult rightResult = inferrer.inferExpression(
         right, const UnknownType(), typeNeeded,
         isVoidAllowed: false);
 
-    assert(equalsTarget.isInstanceMember || equalsTarget.isNever);
+    if (inferrer.useNewMethodInvocationEncoding) {
+      if (_isNull(right)) {
+        equals = new EqualsNull(left, isNot: isNot)..fileOffset = fileOffset;
+      } else if (_isNull(left)) {
+        equals = new EqualsNull(rightResult.expression, isNot: isNot)
+          ..fileOffset = fileOffset;
+      }
+      if (equals != null) {
+        inferrer.flowAnalysis.equalityOp_end(
+            equals, rightResult.expression, rightResult.inferredType,
+            notEqual: isNot);
+        return new ExpressionInferenceResult(
+            inferrer.coreTypes.boolRawType(inferrer.library.nonNullable),
+            equals);
+      }
+    }
+
+    ObjectAccessTarget equalsTarget = inferrer.findInterfaceMember(
+        leftType, equalsName, fileOffset,
+        includeExtensionMethods: true);
+
+    assert(
+        equalsTarget.isInstanceMember ||
+            equalsTarget.isObjectMember ||
+            equalsTarget.isNever,
+        "Unexpected equals target $equalsTarget for "
+        "$left ($leftType) == $right.");
     if (inferrer.instrumentation != null && leftType == const DynamicType()) {
       inferrer.instrumentation.record(
           inferrer.uriForInstrumentation,
@@ -3687,17 +3747,43 @@
         nullabilityNullTypeErrorTemplate:
             templateArgumentTypeNotAssignableNullabilityNullType);
 
-    Expression equals = new MethodInvocation(
-        left,
-        equalsName,
-        new Arguments(<Expression>[
-          right,
-        ])
-          ..fileOffset = fileOffset,
-        equalsTarget.member)
-      ..fileOffset = fileOffset;
-    if (isNot) {
-      equals = new Not(equals)..fileOffset = fileOffset;
+    if (inferrer.useNewMethodInvocationEncoding) {
+      if (equalsTarget.isInstanceMember || equalsTarget.isObjectMember) {
+        FunctionType functionType =
+            inferrer.getFunctionType(equalsTarget, leftType);
+        equals = new EqualsCall(left, right,
+            isNot: isNot,
+            functionType: functionType,
+            interfaceTarget: equalsTarget.member)
+          ..fileOffset = fileOffset;
+      } else {
+        assert(equalsTarget.isNever);
+        FunctionType functionType = new FunctionType(
+            [const DynamicType()],
+            const NeverType(Nullability.nonNullable),
+            inferrer.library.nonNullable);
+        // Ensure operator == member even for `Never`.
+        Member target = inferrer
+            .findInterfaceMember(const DynamicType(), equalsName, -1,
+                instrumented: false)
+            .member;
+        equals = new EqualsCall(left, right,
+            isNot: isNot, functionType: functionType, interfaceTarget: target)
+          ..fileOffset = fileOffset;
+      }
+    } else {
+      equals = new MethodInvocation(
+          left,
+          equalsName,
+          new Arguments(<Expression>[
+            right,
+          ])
+            ..fileOffset = fileOffset,
+          equalsTarget.member)
+        ..fileOffset = fileOffset;
+      if (isNot) {
+        equals = new Not(equals)..fileOffset = fileOffset;
+      }
     }
     inferrer.flowAnalysis.equalityOp_end(
         equals, right, rightResult.inferredType,
@@ -3769,6 +3855,10 @@
               isNonNullableByDefault: inferrer.isNonNullableByDefault);
     }
 
+    if (!inferrer.isNonNullableByDefault) {
+      binaryType = legacyErasure(binaryType);
+    }
+
     Expression binary;
     switch (binaryTarget.kind) {
       case ObjectAccessTargetKind.missing:
@@ -3792,14 +3882,81 @@
               ..fileOffset = fileOffset)
           ..fileOffset = fileOffset;
         break;
-      case ObjectAccessTargetKind.instanceMember:
-      case ObjectAccessTargetKind.nullableInstanceMember:
       case ObjectAccessTargetKind.invalid:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          binary = new DynamicInvocation(
+              DynamicAccessKind.Invalid,
+              left,
+              binaryName,
+              new Arguments(<Expression>[
+                right,
+              ])
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          binary = new MethodInvocation(
+              left,
+              binaryName,
+              new Arguments(<Expression>[
+                right,
+              ])
+                ..fileOffset = fileOffset,
+              binaryTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
       case ObjectAccessTargetKind.callFunction:
       case ObjectAccessTargetKind.nullableCallFunction:
       case ObjectAccessTargetKind.dynamic:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          binary = new DynamicInvocation(
+              DynamicAccessKind.Dynamic,
+              left,
+              binaryName,
+              new Arguments(<Expression>[
+                right,
+              ])
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          binary = new MethodInvocation(
+              left,
+              binaryName,
+              new Arguments(<Expression>[
+                right,
+              ])
+                ..fileOffset = fileOffset,
+              binaryTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
       case ObjectAccessTargetKind.never:
-        if (binaryTarget.isInstanceMember &&
+        if (inferrer.useNewMethodInvocationEncoding) {
+          binary = new DynamicInvocation(
+              DynamicAccessKind.Never,
+              left,
+              binaryName,
+              new Arguments(<Expression>[
+                right,
+              ])
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          binary = new MethodInvocation(
+              left,
+              binaryName,
+              new Arguments(<Expression>[
+                right,
+              ])
+                ..fileOffset = fileOffset,
+              binaryTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
+      case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
+      case ObjectAccessTargetKind.nullableInstanceMember:
+        if ((binaryTarget.isInstanceMember || binaryTarget.isObjectMember) &&
             inferrer.instrumentation != null &&
             leftType == const DynamicType()) {
           inferrer.instrumentation.record(
@@ -3809,15 +3966,30 @@
               new InstrumentationValueForMember(binaryTarget.member));
         }
 
-        binary = new MethodInvocation(
-            left,
-            binaryName,
-            new Arguments(<Expression>[
-              right,
-            ])
-              ..fileOffset = fileOffset,
-            binaryTarget.member)
-          ..fileOffset = fileOffset;
+        if (inferrer.useNewMethodInvocationEncoding) {
+          binary = new InstanceInvocation(
+              InstanceAccessKind.Instance,
+              left,
+              binaryName,
+              new Arguments(<Expression>[
+                right,
+              ])
+                ..fileOffset = fileOffset,
+              functionType: new FunctionType(
+                  [rightType], binaryType, inferrer.library.nonNullable),
+              interfaceTarget: binaryTarget.member)
+            ..fileOffset = fileOffset;
+        } else {
+          binary = new MethodInvocation(
+              left,
+              binaryName,
+              new Arguments(<Expression>[
+                right,
+              ])
+                ..fileOffset = fileOffset,
+              binaryTarget.member)
+            ..fileOffset = fileOffset;
+        }
 
         if (binaryCheckKind ==
             MethodContravarianceCheckKind.checkMethodReturn) {
@@ -3837,10 +4009,6 @@
         break;
     }
 
-    if (!inferrer.isNonNullableByDefault) {
-      binaryType = legacyErasure(binaryType);
-    }
-
     if (!inferrer.isTopLevel && binaryTarget.isNullable) {
       return new ExpressionInferenceResult(
           binaryType,
@@ -3893,14 +4061,54 @@
               ..fileOffset = fileOffset)
           ..fileOffset = fileOffset;
         break;
-      case ObjectAccessTargetKind.instanceMember:
-      case ObjectAccessTargetKind.nullableInstanceMember:
       case ObjectAccessTargetKind.invalid:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          unary = new DynamicInvocation(DynamicAccessKind.Invalid, expression,
+              unaryName, new Arguments(<Expression>[])..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          unary = new MethodInvocation(
+              expression,
+              unaryName,
+              new Arguments(<Expression>[])..fileOffset = fileOffset,
+              unaryTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
+      case ObjectAccessTargetKind.never:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          unary = new DynamicInvocation(DynamicAccessKind.Never, expression,
+              unaryName, new Arguments(<Expression>[])..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          unary = new MethodInvocation(
+              expression,
+              unaryName,
+              new Arguments(<Expression>[])..fileOffset = fileOffset,
+              unaryTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
       case ObjectAccessTargetKind.callFunction:
       case ObjectAccessTargetKind.nullableCallFunction:
       case ObjectAccessTargetKind.dynamic:
-      case ObjectAccessTargetKind.never:
-        if (unaryTarget.isInstanceMember &&
+        if (inferrer.useNewMethodInvocationEncoding) {
+          unary = new DynamicInvocation(DynamicAccessKind.Dynamic, expression,
+              unaryName, new Arguments(<Expression>[])..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          unary = new MethodInvocation(
+              expression,
+              unaryName,
+              new Arguments(<Expression>[])..fileOffset = fileOffset,
+              unaryTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
+      case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
+      case ObjectAccessTargetKind.nullableInstanceMember:
+        if ((unaryTarget.isInstanceMember || unaryTarget.isObjectMember) &&
             inferrer.instrumentation != null &&
             expressionType == const DynamicType()) {
           inferrer.instrumentation.record(
@@ -3910,12 +4118,24 @@
               new InstrumentationValueForMember(unaryTarget.member));
         }
 
-        unary = new MethodInvocation(
-            expression,
-            unaryName,
-            new Arguments(<Expression>[])..fileOffset = fileOffset,
-            unaryTarget.member)
-          ..fileOffset = fileOffset;
+        if (inferrer.useNewMethodInvocationEncoding) {
+          unary = new InstanceInvocation(
+              InstanceAccessKind.Instance,
+              expression,
+              unaryName,
+              new Arguments(<Expression>[])..fileOffset = fileOffset,
+              functionType: new FunctionType(
+                  <DartType>[], unaryType, inferrer.library.nonNullable),
+              interfaceTarget: unaryTarget.member)
+            ..fileOffset = fileOffset;
+        } else {
+          unary = new MethodInvocation(
+              expression,
+              unaryName,
+              new Arguments(<Expression>[])..fileOffset = fileOffset,
+              unaryTarget.member)
+            ..fileOffset = fileOffset;
+        }
 
         if (unaryCheckKind == MethodContravarianceCheckKind.checkMethodReturn) {
           if (inferrer.instrumentation != null) {
@@ -3965,6 +4185,7 @@
       DartType receiverType,
       ObjectAccessTarget readTarget,
       Expression readIndex,
+      DartType indexType,
       MethodContravarianceCheckKind readCheckKind) {
     Expression read;
     DartType readType = inferrer.getReturnType(readTarget, receiverType);
@@ -3989,22 +4210,118 @@
               ..fileOffset = fileOffset)
           ..fileOffset = fileOffset;
         break;
-      case ObjectAccessTargetKind.instanceMember:
-      case ObjectAccessTargetKind.nullableInstanceMember:
       case ObjectAccessTargetKind.invalid:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          read = new DynamicInvocation(
+              DynamicAccessKind.Invalid,
+              readReceiver,
+              indexGetName,
+              new Arguments(<Expression>[
+                readIndex,
+              ])
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          read = new MethodInvocation(
+              readReceiver,
+              indexGetName,
+              new Arguments(<Expression>[
+                readIndex,
+              ])
+                ..fileOffset = fileOffset,
+              readTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
+      case ObjectAccessTargetKind.never:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          read = new DynamicInvocation(
+              DynamicAccessKind.Never,
+              readReceiver,
+              indexGetName,
+              new Arguments(<Expression>[
+                readIndex,
+              ])
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          read = new MethodInvocation(
+              readReceiver,
+              indexGetName,
+              new Arguments(<Expression>[
+                readIndex,
+              ])
+                ..fileOffset = fileOffset,
+              readTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
       case ObjectAccessTargetKind.callFunction:
       case ObjectAccessTargetKind.nullableCallFunction:
       case ObjectAccessTargetKind.dynamic:
-      case ObjectAccessTargetKind.never:
-        read = new MethodInvocation(
-            readReceiver,
-            indexGetName,
-            new Arguments(<Expression>[
-              readIndex,
-            ])
-              ..fileOffset = fileOffset,
-            readTarget.member)
-          ..fileOffset = fileOffset;
+        if (inferrer.useNewMethodInvocationEncoding) {
+          read = new DynamicInvocation(
+              DynamicAccessKind.Dynamic,
+              readReceiver,
+              indexGetName,
+              new Arguments(<Expression>[
+                readIndex,
+              ])
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          read = new MethodInvocation(
+              readReceiver,
+              indexGetName,
+              new Arguments(<Expression>[
+                readIndex,
+              ])
+                ..fileOffset = fileOffset,
+              readTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
+      case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
+      case ObjectAccessTargetKind.nullableInstanceMember:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          InstanceAccessKind kind;
+          switch (readTarget.kind) {
+            case ObjectAccessTargetKind.instanceMember:
+              kind = InstanceAccessKind.Instance;
+              break;
+            case ObjectAccessTargetKind.nullableInstanceMember:
+              kind = InstanceAccessKind.Nullable;
+              break;
+            case ObjectAccessTargetKind.objectMember:
+              kind = InstanceAccessKind.Object;
+              break;
+            default:
+              throw new UnsupportedError('Unexpected target kind $readTarget');
+          }
+          read = new InstanceInvocation(
+              kind,
+              readReceiver,
+              indexGetName,
+              new Arguments(<Expression>[
+                readIndex,
+              ])
+                ..fileOffset = fileOffset,
+              functionType: new FunctionType(
+                  [indexType], readType, inferrer.library.nonNullable),
+              interfaceTarget: readTarget.member)
+            ..fileOffset = fileOffset;
+        } else {
+          read = new MethodInvocation(
+              readReceiver,
+              indexGetName,
+              new Arguments(<Expression>[
+                readIndex,
+              ])
+                ..fileOffset = fileOffset,
+              readTarget.member)
+            ..fileOffset = fileOffset;
+        }
         if (readCheckKind == MethodContravarianceCheckKind.checkMethodReturn) {
           if (inferrer.instrumentation != null) {
             inferrer.instrumentation.record(
@@ -4051,7 +4368,9 @@
       DartType receiverType,
       ObjectAccessTarget writeTarget,
       Expression index,
-      Expression value) {
+      DartType indexType,
+      Expression value,
+      DartType valueType) {
     Expression write;
     switch (writeTarget.kind) {
       case ObjectAccessTargetKind.missing:
@@ -4076,19 +4395,104 @@
               ..fileOffset = fileOffset)
           ..fileOffset = fileOffset;
         break;
-      case ObjectAccessTargetKind.instanceMember:
-      case ObjectAccessTargetKind.nullableInstanceMember:
       case ObjectAccessTargetKind.invalid:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          write = new DynamicInvocation(
+              DynamicAccessKind.Invalid,
+              receiver,
+              indexSetName,
+              new Arguments(<Expression>[index, value])
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          write = new MethodInvocation(
+              receiver,
+              indexSetName,
+              new Arguments(<Expression>[index, value])
+                ..fileOffset = fileOffset,
+              writeTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
+      case ObjectAccessTargetKind.never:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          write = new DynamicInvocation(
+              DynamicAccessKind.Never,
+              receiver,
+              indexSetName,
+              new Arguments(<Expression>[index, value])
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+        } else {
+          write = new MethodInvocation(
+              receiver,
+              indexSetName,
+              new Arguments(<Expression>[index, value])
+                ..fileOffset = fileOffset,
+              writeTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
       case ObjectAccessTargetKind.callFunction:
       case ObjectAccessTargetKind.nullableCallFunction:
       case ObjectAccessTargetKind.dynamic:
-      case ObjectAccessTargetKind.never:
-        write = new MethodInvocation(
-            receiver,
-            indexSetName,
-            new Arguments(<Expression>[index, value])..fileOffset = fileOffset,
-            writeTarget.member)
-          ..fileOffset = fileOffset;
+        if (inferrer.useNewMethodInvocationEncoding) {
+          write = new DynamicInvocation(
+              DynamicAccessKind.Dynamic,
+              receiver,
+              indexSetName,
+              new Arguments(<Expression>[index, value])
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset;
+          break;
+        } else {
+          write = new MethodInvocation(
+              receiver,
+              indexSetName,
+              new Arguments(<Expression>[index, value])
+                ..fileOffset = fileOffset,
+              writeTarget.member)
+            ..fileOffset = fileOffset;
+          break;
+        }
+        break;
+      case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
+      case ObjectAccessTargetKind.nullableInstanceMember:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          InstanceAccessKind kind;
+          switch (writeTarget.kind) {
+            case ObjectAccessTargetKind.instanceMember:
+              kind = InstanceAccessKind.Instance;
+              break;
+            case ObjectAccessTargetKind.nullableInstanceMember:
+              kind = InstanceAccessKind.Nullable;
+              break;
+            case ObjectAccessTargetKind.objectMember:
+              kind = InstanceAccessKind.Object;
+              break;
+            default:
+              throw new UnsupportedError('Unexpected target kind $writeTarget');
+          }
+          write = new InstanceInvocation(
+              kind,
+              receiver,
+              indexSetName,
+              new Arguments(<Expression>[index, value])
+                ..fileOffset = fileOffset,
+              functionType: new FunctionType([indexType, valueType],
+                  const VoidType(), inferrer.library.nonNullable),
+              interfaceTarget: writeTarget.member)
+            ..fileOffset = fileOffset;
+        } else {
+          write = new MethodInvocation(
+              receiver,
+              indexSetName,
+              new Arguments(<Expression>[index, value])
+                ..fileOffset = fileOffset,
+              writeTarget.member)
+            ..fileOffset = fileOffset;
+        }
         break;
     }
     if (!inferrer.isTopLevel && writeTarget.isNullable) {
@@ -4167,14 +4571,49 @@
             break;
         }
         break;
-      case ObjectAccessTargetKind.instanceMember:
-      case ObjectAccessTargetKind.nullableInstanceMember:
+      case ObjectAccessTargetKind.never:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          read = new DynamicGet(DynamicAccessKind.Never, receiver, propertyName)
+            ..fileOffset = fileOffset;
+        } else {
+          read = new PropertyGet(receiver, propertyName, readTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
+      case ObjectAccessTargetKind.dynamic:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          read =
+              new DynamicGet(DynamicAccessKind.Dynamic, receiver, propertyName)
+                ..fileOffset = fileOffset;
+        } else {
+          read = new PropertyGet(receiver, propertyName, readTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
       case ObjectAccessTargetKind.invalid:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          read =
+              new DynamicGet(DynamicAccessKind.Invalid, receiver, propertyName)
+                ..fileOffset = fileOffset;
+        } else {
+          read = new PropertyGet(receiver, propertyName, readTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
       case ObjectAccessTargetKind.callFunction:
       case ObjectAccessTargetKind.nullableCallFunction:
-      case ObjectAccessTargetKind.dynamic:
-      case ObjectAccessTargetKind.never:
-        if (readTarget.isInstanceMember &&
+        if (inferrer.useNewMethodInvocationEncoding) {
+          read = new FunctionTearOff(receiver)..fileOffset = fileOffset;
+        } else {
+          read = new PropertyGet(receiver, propertyName, readTarget.member)
+            ..fileOffset = fileOffset;
+        }
+        break;
+      case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
+      case ObjectAccessTargetKind.nullableInstanceMember:
+        Member member = readTarget.member;
+        if ((readTarget.isInstanceMember || readTarget.isObjectMember) &&
             inferrer.instrumentation != null &&
             receiverType == const DynamicType()) {
           inferrer.instrumentation.record(
@@ -4183,10 +4622,37 @@
               'target',
               new InstrumentationValueForMember(readTarget.member));
         }
-        read = new PropertyGet(receiver, propertyName, readTarget.member)
-          ..fileOffset = fileOffset;
+        if (inferrer.useNewMethodInvocationEncoding) {
+          InstanceAccessKind kind;
+          switch (readTarget.kind) {
+            case ObjectAccessTargetKind.instanceMember:
+              kind = InstanceAccessKind.Instance;
+              break;
+            case ObjectAccessTargetKind.nullableInstanceMember:
+              kind = InstanceAccessKind.Nullable;
+              break;
+            case ObjectAccessTargetKind.objectMember:
+              kind = InstanceAccessKind.Object;
+              break;
+            default:
+              throw new UnsupportedError('Unexpected target kind $readTarget');
+          }
+          if (member is Procedure && member.kind == ProcedureKind.Method) {
+            read = new InstanceTearOff(kind, receiver, propertyName,
+                interfaceTarget: readTarget.member, resultType: readType)
+              ..fileOffset = fileOffset;
+          } else {
+            read = new InstanceGet(kind, receiver, propertyName,
+                interfaceTarget: readTarget.member, resultType: readType)
+              ..fileOffset = fileOffset;
+          }
+        } else {
+          read = new PropertyGet(receiver, propertyName, readTarget.member)
+            ..fileOffset = fileOffset;
+        }
         bool checkReturn = false;
-        if (readTarget.isInstanceMember && !isThisReceiver) {
+        if ((readTarget.isInstanceMember || readTarget.isObjectMember) &&
+            !isThisReceiver) {
           Member interfaceMember = readTarget.member;
           if (interfaceMember is Procedure) {
             checkReturn =
@@ -4213,7 +4679,6 @@
             ..isForNonNullableByDefault = inferrer.isNonNullableByDefault
             ..fileOffset = fileOffset;
         }
-        Member member = readTarget.member;
         if (member is Procedure && member.kind == ProcedureKind.Method) {
           readResult = inferrer.instantiateTearOff(readType, typeContext, read);
         }
@@ -4297,16 +4762,67 @@
             ..fileOffset = fileOffset;
         }
         break;
-      case ObjectAccessTargetKind.instanceMember:
-      case ObjectAccessTargetKind.nullableInstanceMember:
       case ObjectAccessTargetKind.invalid:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          write = new DynamicSet(
+              DynamicAccessKind.Invalid, receiver, propertyName, value)
+            ..fileOffset = fileOffset;
+        } else {
+          write =
+              new PropertySet(receiver, propertyName, value, writeTarget.member)
+                ..fileOffset = fileOffset;
+        }
+        break;
+      case ObjectAccessTargetKind.never:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          write = new DynamicSet(
+              DynamicAccessKind.Never, receiver, propertyName, value)
+            ..fileOffset = fileOffset;
+        } else {
+          write =
+              new PropertySet(receiver, propertyName, value, writeTarget.member)
+                ..fileOffset = fileOffset;
+        }
+        break;
       case ObjectAccessTargetKind.callFunction:
       case ObjectAccessTargetKind.nullableCallFunction:
       case ObjectAccessTargetKind.dynamic:
-      case ObjectAccessTargetKind.never:
-        write =
-            new PropertySet(receiver, propertyName, value, writeTarget.member)
-              ..fileOffset = fileOffset;
+        if (inferrer.useNewMethodInvocationEncoding) {
+          write = new DynamicSet(
+              DynamicAccessKind.Dynamic, receiver, propertyName, value)
+            ..fileOffset = fileOffset;
+        } else {
+          write =
+              new PropertySet(receiver, propertyName, value, writeTarget.member)
+                ..fileOffset = fileOffset;
+        }
+        break;
+      case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
+      case ObjectAccessTargetKind.nullableInstanceMember:
+        if (inferrer.useNewMethodInvocationEncoding) {
+          InstanceAccessKind kind;
+          switch (writeTarget.kind) {
+            case ObjectAccessTargetKind.instanceMember:
+              kind = InstanceAccessKind.Instance;
+              break;
+            case ObjectAccessTargetKind.nullableInstanceMember:
+              kind = InstanceAccessKind.Nullable;
+              break;
+            case ObjectAccessTargetKind.objectMember:
+              kind = InstanceAccessKind.Object;
+              break;
+            default:
+              throw new UnsupportedError('Unexpected target kind $writeTarget');
+          }
+          write = new InstanceSet(kind, receiver, propertyName, value,
+              interfaceTarget: writeTarget.member)
+            ..fileOffset = fileOffset;
+        } else {
+          write =
+              new PropertySet(receiver, propertyName, value, writeTarget.member)
+                ..fileOffset = fileOffset;
+        }
         break;
     }
     if (!inferrer.isTopLevel && writeTarget.isNullable) {
@@ -4360,8 +4876,14 @@
     readIndex = inferrer.ensureAssignable(
         readIndexType, indexResult.inferredType, readIndex);
 
-    ExpressionInferenceResult readResult = _computeIndexGet(node.readOffset,
-        readReceiver, receiverType, readTarget, readIndex, readCheckKind);
+    ExpressionInferenceResult readResult = _computeIndexGet(
+        node.readOffset,
+        readReceiver,
+        receiverType,
+        readTarget,
+        readIndex,
+        readIndexType,
+        readCheckKind);
     Expression read = readResult.expression;
     DartType readType = readResult.inferredType;
 
@@ -4412,8 +4934,15 @@
       valueExpression = createVariableGet(valueVariable);
     }
 
-    Expression write = _computeIndexSet(node.writeOffset, writeReceiver,
-        receiverType, writeTarget, writeIndex, valueExpression);
+    Expression write = _computeIndexSet(
+        node.writeOffset,
+        writeReceiver,
+        receiverType,
+        writeTarget,
+        writeIndex,
+        writeIndexType,
+        valueExpression,
+        valueType);
 
     Expression inner;
     if (node.forEffect) {
@@ -4629,7 +5158,7 @@
     if (readTarget.isMissing) {
       read = inferrer.createMissingSuperIndexGet(node.readOffset, readIndex);
     } else {
-      assert(readTarget.isInstanceMember);
+      assert(readTarget.isInstanceMember || readTarget.isObjectMember);
       inferrer.instrumentation?.record(
           inferrer.uriForInstrumentation,
           node.readOffset,
@@ -4701,7 +5230,7 @@
       write = inferrer.createMissingSuperIndexSet(
           node.writeOffset, writeIndex, valueExpression);
     } else {
-      assert(writeTarget.isInstanceMember);
+      assert(writeTarget.isInstanceMember || writeTarget.isObjectMember);
       inferrer.instrumentation?.record(
           inferrer.uriForInstrumentation,
           node.writeOffset,
@@ -4812,6 +5341,7 @@
         receiverType,
         readTarget,
         readIndex,
+        readIndexType,
         MethodContravarianceCheckKind.none);
     Expression read = readResult.expression;
     DartType readType = readResult.inferredType;
@@ -4864,8 +5394,15 @@
       valueExpression = createVariableGet(valueVariable);
     }
 
-    Expression write = _computeIndexSet(node.writeOffset, writeReceiver,
-        receiverType, writeTarget, writeIndex, valueExpression);
+    Expression write = _computeIndexSet(
+        node.writeOffset,
+        writeReceiver,
+        receiverType,
+        writeTarget,
+        writeIndex,
+        writeIndexType,
+        valueExpression,
+        valueType);
 
     Expression replacement;
     if (node.forEffect) {
@@ -4962,7 +5499,7 @@
     ObjectAccessTarget target = inferrer.findInterfaceMember(
         receiverType, node.name, node.fileOffset,
         setter: true, instrumented: true, includeExtensionMethods: true);
-    if (target.isInstanceMember) {
+    if (target.isInstanceMember || target.isObjectMember) {
       if (inferrer.instrumentation != null &&
           receiverType == const DynamicType()) {
         inferrer.instrumentation.record(
@@ -5059,8 +5596,8 @@
       //           receiverVariable.name = value : null)
       //
 
-      MethodInvocation readEqualsNull =
-          createEqualsNull(node.readOffset, read, readEqualsMember);
+      Expression readEqualsNull =
+          inferrer.createEqualsNull(node.readOffset, read, readEqualsMember);
       replacement = new ConditionalExpression(readEqualsNull, write,
           new NullLiteral()..fileOffset = node.writeOffset, inferredType);
     } else {
@@ -5074,8 +5611,8 @@
       //
       assert(readVariable != null);
 
-      MethodInvocation readEqualsNull =
-          createEqualsNull(receiverVariable.fileOffset, read, readEqualsMember);
+      Expression readEqualsNull = inferrer.createEqualsNull(
+          receiverVariable.fileOffset, read, readEqualsMember);
       VariableGet variableGet = createVariableGet(readVariable);
       if (inferrer.library.isNonNullableByDefault &&
           !identical(nonNullableReadType, readType)) {
@@ -5280,7 +5817,11 @@
     }
 
     if (target is Procedure && target.kind == ProcedureKind.Method) {
-      return inferrer.instantiateTearOff(type, typeContext, node);
+      Expression tearOff = node;
+      if (inferrer.useNewMethodInvocationEncoding) {
+        tearOff = new StaticTearOff(node.target)..fileOffset = node.fileOffset;
+      }
+      return inferrer.instantiateTearOff(type, typeContext, tearOff);
     } else {
       return new ExpressionInferenceResult(type, node);
     }
@@ -5396,7 +5937,7 @@
     ObjectAccessTarget writeTarget = inferrer.findInterfaceMember(
         receiverType, node.name, node.fileOffset,
         setter: true, instrumented: true);
-    if (writeTarget.isInstanceMember) {
+    if (writeTarget.isInstanceMember || writeTarget.isObjectMember) {
       node.interfaceTarget = writeTarget.member;
     }
     DartType writeContext = inferrer.getSetterType(writeTarget, receiverType);
@@ -5682,11 +6223,18 @@
     DartType resultType = rhsResult.inferredType;
     Expression resultExpression;
     if (variable.lateSetter != null) {
-      resultExpression = new MethodInvocation(
-          new VariableGet(variable.lateSetter)..fileOffset = node.fileOffset,
-          callName,
-          new Arguments(<Expression>[rhs])..fileOffset = node.fileOffset)
-        ..fileOffset = node.fileOffset;
+      if (inferrer.useNewMethodInvocationEncoding) {
+        resultExpression = new LocalFunctionInvocation(variable.lateSetter,
+            new Arguments(<Expression>[rhs])..fileOffset = node.fileOffset,
+            functionType: variable.lateSetter.type)
+          ..fileOffset = node.fileOffset;
+      } else {
+        resultExpression = new MethodInvocation(
+            new VariableGet(variable.lateSetter)..fileOffset = node.fileOffset,
+            callName,
+            new Arguments(<Expression>[rhs])..fileOffset = node.fileOffset)
+          ..fileOffset = node.fileOffset;
+      }
       // Future calls to flow analysis will be using `resultExpression` to refer
       // to the variable set, so instruct flow analysis to forward the
       // expression information.
@@ -5837,7 +6385,11 @@
           new FunctionNode(
               node.initializer == null
                   ? late_lowering.createGetterBodyWithoutInitializer(
-                      inferrer.coreTypes, fileOffset, node.name, node.type,
+                      inferrer.coreTypes,
+                      fileOffset,
+                      node.name,
+                      node.type,
+                      inferrer.useNewMethodInvocationEncoding,
                       createVariableRead: createVariableRead,
                       createIsSetRead: createIsSetRead,
                       isSetEncoding: isSetEncoding,
@@ -5849,6 +6401,7 @@
                           node.name,
                           node.type,
                           node.initializer,
+                          inferrer.useNewMethodInvocationEncoding,
                           createVariableRead: createVariableRead,
                           createVariableWrite: createVariableWrite,
                           createIsSetRead: createIsSetRead,
@@ -5861,6 +6414,7 @@
                           node.name,
                           node.type,
                           node.initializer,
+                          inferrer.useNewMethodInvocationEncoding,
                           createVariableRead: createVariableRead,
                           createVariableWrite: createVariableWrite,
                           createIsSetRead: createIsSetRead,
@@ -5893,6 +6447,7 @@
                             node.name,
                             setterParameter,
                             node.type,
+                            inferrer.useNewMethodInvocationEncoding,
                             shouldReturnValue: true,
                             createVariableRead: createVariableRead,
                             createVariableWrite: createVariableWrite,
@@ -5972,11 +6527,18 @@
     if (variable.isLocalFunction) {
       return inferrer.instantiateTearOff(resultType, typeContext, node);
     } else if (variable.lateGetter != null) {
-      resultExpression = new MethodInvocation(
-          new VariableGet(variable.lateGetter)..fileOffset = node.fileOffset,
-          callName,
-          new Arguments(<Expression>[])..fileOffset = node.fileOffset)
-        ..fileOffset = node.fileOffset;
+      if (inferrer.useNewMethodInvocationEncoding) {
+        resultExpression = new LocalFunctionInvocation(variable.lateGetter,
+            new Arguments(<Expression>[])..fileOffset = node.fileOffset,
+            functionType: variable.lateGetter.type)
+          ..fileOffset = node.fileOffset;
+      } else {
+        resultExpression = new MethodInvocation(
+            new VariableGet(variable.lateGetter)..fileOffset = node.fileOffset,
+            callName,
+            new Arguments(<Expression>[])..fileOffset = node.fileOffset)
+          ..fileOffset = node.fileOffset;
+      }
       // Future calls to flow analysis will be using `resultExpression` to refer
       // to the variable get, so instruct flow analysis to forward the
       // expression information.
@@ -6235,6 +6797,97 @@
       }
     }
   }
+
+  @override
+  ExpressionInferenceResult visitDynamicGet(
+      DynamicGet node, DartType typeContext) {
+    // TODO: implement visitDynamicGet
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitInstanceGet(
+      InstanceGet node, DartType typeContext) {
+    // TODO: implement visitInstanceGet
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitInstanceTearOff(
+      InstanceTearOff node, DartType typeContext) {
+    // TODO: implement visitInstanceTearOff
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitDynamicInvocation(
+      DynamicInvocation node, DartType typeContext) {
+    // TODO: implement visitDynamicInvocation
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitDynamicSet(
+      DynamicSet node, DartType typeContext) {
+    // TODO: implement visitDynamicSet
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitEqualsCall(
+      EqualsCall node, DartType typeContext) {
+    // TODO: implement visitEqualsCall
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitEqualsNull(
+      EqualsNull node, DartType typeContext) {
+    // TODO: implement visitEqualsNull
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitFunctionInvocation(
+      FunctionInvocation node, DartType typeContext) {
+    // TODO: implement visitFunctionInvocation
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitInstanceInvocation(
+      InstanceInvocation node, DartType typeContext) {
+    // TODO: implement visitInstanceInvocation
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitInstanceSet(
+      InstanceSet node, DartType typeContext) {
+    // TODO: implement visitInstanceSet
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitLocalFunctionInvocation(
+      LocalFunctionInvocation node, DartType typeContext) {
+    // TODO: implement visitLocalFunctionInvocation
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitStaticTearOff(
+      StaticTearOff node, DartType typeContext) {
+    // TODO: implement visitStaticTearOff
+    throw new UnimplementedError();
+  }
+
+  @override
+  ExpressionInferenceResult visitFunctionTearOff(
+      FunctionTearOff node, DartType arg) {
+    // TODO: implement visitFunctionTearOff
+    throw new UnimplementedError();
+  }
 }
 
 class ForInResult {
@@ -6320,7 +6973,7 @@
     if (error != null) {
       _rhs = error;
     } else {
-      if (writeTarget.isInstanceMember) {
+      if (writeTarget.isInstanceMember || writeTarget.isObjectMember) {
         if (inferrer.instrumentation != null &&
             receiverType == const DynamicType()) {
           inferrer.instrumentation.record(
@@ -6368,7 +7021,7 @@
     ObjectAccessTarget writeTarget = inferrer.findInterfaceMember(
         receiverType, superPropertySet.name, superPropertySet.fileOffset,
         setter: true, instrumented: true);
-    if (writeTarget.isInstanceMember) {
+    if (writeTarget.isInstanceMember || writeTarget.isObjectMember) {
       superPropertySet.interfaceTarget = writeTarget.member;
     }
     return _writeType = inferrer.getSetterType(writeTarget, receiverType);
diff --git a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index 9504a6e..56a9bd8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -2846,6 +2846,29 @@
   String toString() {
     return "CompoundIndexSet(${toStringInternal()})";
   }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver);
+    printer.write('[');
+    printer.writeExpression(index);
+    printer.write(']');
+    if (forPostIncDec &&
+        (binaryName.text == '+' || binaryName.text == '-') &&
+        rhs is IntLiteral &&
+        (rhs as IntLiteral).value == 1) {
+      if (binaryName.text == '+') {
+        printer.write('++');
+      } else {
+        printer.write('--');
+      }
+    } else {
+      printer.write(' ');
+      printer.write(binaryName.text);
+      printer.write('= ');
+      printer.writeExpression(rhs);
+    }
+  }
 }
 
 /// Internal expression representing a null-aware compound assignment.
@@ -3749,20 +3772,6 @@
   return new VariableGet(variable)..fileOffset = variable.fileOffset;
 }
 
-/// Creates a `e == null` test for the expression [left] using the [fileOffset]
-/// as file offset for the created nodes and [equalsMember] as the interface
-/// target of the created method invocation.
-MethodInvocation createEqualsNull(
-    int fileOffset, Expression left, Member equalsMember) {
-  return new MethodInvocation(
-      left,
-      equalsName,
-      new Arguments(<Expression>[new NullLiteral()..fileOffset = fileOffset])
-        ..fileOffset = fileOffset)
-    ..fileOffset = fileOffset
-    ..interfaceTarget = equalsMember;
-}
-
 ExpressionStatement createExpressionStatement(Expression expression) {
   return new ExpressionStatement(expression)
     ..fileOffset = expression.fileOffset;
diff --git a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
index 02ee9f2..93eea7f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
@@ -20,8 +20,13 @@
 ///
 /// Late final fields and locals need to detect writes during initialization and
 /// therefore uses [createGetterWithInitializerWithRecheck] instead.
-Statement createGetterWithInitializer(CoreTypes coreTypes, int fileOffset,
-    String name, DartType type, Expression initializer,
+Statement createGetterWithInitializer(
+    CoreTypes coreTypes,
+    int fileOffset,
+    String name,
+    DartType type,
+    Expression initializer,
+    bool useNewMethodInvocationEncoding,
     {Expression createVariableRead({bool needsPromotion}),
     Expression createVariableWrite(Expression value),
     Expression createIsSetRead(),
@@ -94,23 +99,27 @@
           createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
           type: type.withDeclaredNullability(Nullability.nullable))
         ..fileOffset = fileOffset;
-      return new ReturnStatement(
-          new Let(
-              variable,
-              new ConditionalExpression(
-                  new MethodInvocation(
+      return new ReturnStatement(new Let(
+          variable,
+          new ConditionalExpression(
+              useNewMethodInvocationEncoding
+                  ? (new EqualsNull(
+                      new VariableGet(variable)..fileOffset = fileOffset,
+                      isNot: false)
+                    ..fileOffset = fileOffset)
+                  : new MethodInvocation(
                       new VariableGet(variable)..fileOffset = fileOffset,
                       equalsName,
                       new Arguments(<Expression>[
                         new NullLiteral()..fileOffset = fileOffset
                       ])
                         ..fileOffset = fileOffset)
-                    ..fileOffset = fileOffset,
-                  createVariableWrite(initializer)..fileOffset = fileOffset,
-                  new VariableGet(variable, type)..fileOffset = fileOffset,
-                  type)
-                ..fileOffset = fileOffset)
+                ..fileOffset = fileOffset,
+              createVariableWrite(initializer)..fileOffset = fileOffset,
+              new VariableGet(variable, type)..fileOffset = fileOffset,
+              type)
             ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset)
         ..fileOffset = fileOffset;
   }
   throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
@@ -118,8 +127,13 @@
 
 /// Creates the body for the synthesized getter used to encode the lowering
 /// of a late final field or local with an initializer.
-Statement createGetterWithInitializerWithRecheck(CoreTypes coreTypes,
-    int fileOffset, String name, DartType type, Expression initializer,
+Statement createGetterWithInitializerWithRecheck(
+    CoreTypes coreTypes,
+    int fileOffset,
+    String name,
+    DartType type,
+    Expression initializer,
+    bool useNewMethodInvocationEncoding,
     {Expression createVariableRead({bool needsPromotion}),
     Expression createVariableWrite(Expression value),
     Expression createIsSetRead(),
@@ -240,22 +254,32 @@
           createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
           type: type.withDeclaredNullability(Nullability.nullable))
         ..fileOffset = fileOffset;
-      return new ReturnStatement(
-          new Let(
-              variable,
-              new ConditionalExpression(
-                  new MethodInvocation(
+      return new ReturnStatement(new Let(
+          variable,
+          new ConditionalExpression(
+              useNewMethodInvocationEncoding
+                  ? (new EqualsNull(
+                      new VariableGet(variable)..fileOffset = fileOffset,
+                      isNot: false)
+                    ..fileOffset = fileOffset)
+                  : new MethodInvocation(
                       new VariableGet(variable)..fileOffset = fileOffset,
                       equalsName,
                       new Arguments(<Expression>[
                         new NullLiteral()..fileOffset = fileOffset
                       ])
                         ..fileOffset = fileOffset)
-                    ..fileOffset = fileOffset,
-                  new Let(
-                      temp,
-                      new ConditionalExpression(
-                          new MethodInvocation(
+                ..fileOffset = fileOffset,
+              new Let(
+                  temp,
+                  new ConditionalExpression(
+                      useNewMethodInvocationEncoding
+                          ? (new EqualsNull(
+                              createVariableRead(needsPromotion: false)
+                                ..fileOffset = fileOffset,
+                              isNot: false)
+                            ..fileOffset = fileOffset)
+                          : new MethodInvocation(
                               createVariableRead(needsPromotion: false)
                                 ..fileOffset = fileOffset,
                               equalsName,
@@ -263,17 +287,17 @@
                                 new NullLiteral()..fileOffset = fileOffset
                               ])
                                 ..fileOffset = fileOffset)
-                            ..fileOffset = fileOffset,
-                          createVariableWrite(
-                              new VariableGet(temp)..fileOffset = fileOffset)
-                            ..fileOffset = fileOffset,
-                          exception,
-                          type)
-                        ..fileOffset = fileOffset),
-                  new VariableGet(variable, type)..fileOffset = fileOffset,
-                  type)
-                ..fileOffset = fileOffset)
+                        ..fileOffset = fileOffset,
+                      createVariableWrite(
+                          new VariableGet(temp)..fileOffset = fileOffset)
+                        ..fileOffset = fileOffset,
+                      exception,
+                      type)
+                    ..fileOffset = fileOffset),
+              new VariableGet(variable, type)..fileOffset = fileOffset,
+              type)
             ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset)
         ..fileOffset = fileOffset;
   }
   throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
@@ -282,7 +306,11 @@
 /// Creates the body for the synthesized getter used to encode the lowering
 /// of a late field or local without an initializer.
 Statement createGetterBodyWithoutInitializer(
-    CoreTypes coreTypes, int fileOffset, String name, DartType type,
+    CoreTypes coreTypes,
+    int fileOffset,
+    String name,
+    DartType type,
+    bool useNewMethodInvocationEncoding,
     {Expression createVariableRead({bool needsPromotion}),
     Expression createIsSetRead(),
     IsSetEncoding isSetEncoding,
@@ -346,23 +374,27 @@
           createVariableRead()..fileOffset = fileOffset,
           type: type.withDeclaredNullability(Nullability.nullable))
         ..fileOffset = fileOffset;
-      return new ReturnStatement(
-          new Let(
-              variable,
-              new ConditionalExpression(
-                  new MethodInvocation(
+      return new ReturnStatement(new Let(
+          variable,
+          new ConditionalExpression(
+              useNewMethodInvocationEncoding
+                  ? (new EqualsNull(
+                      new VariableGet(variable)..fileOffset = fileOffset,
+                      isNot: false)
+                    ..fileOffset = fileOffset)
+                  : new MethodInvocation(
                       new VariableGet(variable)..fileOffset = fileOffset,
                       equalsName,
                       new Arguments(<Expression>[
                         new NullLiteral()..fileOffset = fileOffset
                       ])
                         ..fileOffset = fileOffset)
-                    ..fileOffset = fileOffset,
-                  exception,
-                  new VariableGet(variable, type)..fileOffset = fileOffset,
-                  type)
-                ..fileOffset = fileOffset)
+                ..fileOffset = fileOffset,
+              exception,
+              new VariableGet(variable, type)..fileOffset = fileOffset,
+              type)
             ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset)
         ..fileOffset = fileOffset;
   }
   throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
@@ -417,8 +449,13 @@
 
 /// Creates the body for the synthesized setter used to encode the lowering
 /// of a final late field or local.
-Statement createSetterBodyFinal(CoreTypes coreTypes, int fileOffset,
-    String name, VariableDeclaration parameter, DartType type,
+Statement createSetterBodyFinal(
+    CoreTypes coreTypes,
+    int fileOffset,
+    String name,
+    VariableDeclaration parameter,
+    DartType type,
+    bool useNewMethodInvocationEncoding,
     {bool shouldReturnValue,
     Expression createVariableRead(),
     Expression createVariableWrite(Expression value),
@@ -500,12 +537,16 @@
       //      throw '...';
       //    }
       return new IfStatement(
-        new MethodInvocation(
-            createVariableRead()..fileOffset = fileOffset,
-            equalsName,
-            new Arguments(
-                <Expression>[new NullLiteral()..fileOffset = fileOffset])
+        useNewMethodInvocationEncoding
+            ? (new EqualsNull(createVariableRead()..fileOffset = fileOffset,
+                isNot: false)
               ..fileOffset = fileOffset)
+            : new MethodInvocation(
+                createVariableRead()..fileOffset = fileOffset,
+                equalsName,
+                new Arguments(
+                    <Expression>[new NullLiteral()..fileOffset = fileOffset])
+                  ..fileOffset = fileOffset)
           ..fileOffset = fileOffset,
         createReturn(createVariableWrite(
             new VariableGet(parameter)..fileOffset = fileOffset)
diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
index a7a85b9..6d2a8e6 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
@@ -6,46 +6,11 @@
 
 import 'dart:core' hide MapEntry;
 
-import 'package:kernel/ast.dart'
-    show
-        Arguments,
-        AsExpression,
-        Block,
-        BlockExpression,
-        Class,
-        ConditionalExpression,
-        DartType,
-        DynamicType,
-        Expression,
-        ExpressionStatement,
-        Field,
-        ForInStatement,
-        ForStatement,
-        IfStatement,
-        InterfaceType,
-        Let,
-        Library,
-        ListConcatenation,
-        ListLiteral,
-        MapConcatenation,
-        MapEntry,
-        MapLiteral,
-        MethodInvocation,
-        Name,
-        Not,
-        NullLiteral,
-        Procedure,
-        PropertyGet,
-        SetConcatenation,
-        SetLiteral,
-        Statement,
-        StaticInvocation,
-        transformList,
-        TreeNode,
-        VariableDeclaration,
-        VariableGet;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/core_types.dart' show CoreTypes;
+import 'package:kernel/src/legacy_erasure.dart';
+import 'package:kernel/type_algebra.dart';
 
 import 'package:kernel/type_environment.dart'
     show SubtypeCheckMode, TypeEnvironment;
@@ -75,19 +40,25 @@
   final SourceLoader _loader;
   final TypeEnvironment _typeEnvironment;
   final Procedure _listAdd;
+  FunctionType _listAddFunctionType;
   final Procedure _listAddAll;
+  FunctionType _listAddAllFunctionType;
   final Procedure _listOf;
   final Procedure _setFactory;
   final Procedure _setAdd;
+  FunctionType _setAddFunctionType;
   final Procedure _setAddAll;
+  FunctionType _setAddAllFunctionType;
   final Procedure _setOf;
   final Procedure _objectEquals;
   final Procedure _mapEntries;
   final Procedure _mapPut;
+  FunctionType _mapPutFunctionType;
   final Class _mapEntryClass;
   final Field _mapEntryKey;
   final Field _mapEntryValue;
   final SourceLoaderDataForTesting _dataForTesting;
+  final bool useNewMethodInvocationEncoding;
 
   /// Library that contains the transformed nodes.
   ///
@@ -124,7 +95,15 @@
             _loader.coreTypes.index.getMember('dart:core', 'MapEntry', 'key'),
         _mapEntryValue =
             _loader.coreTypes.index.getMember('dart:core', 'MapEntry', 'value'),
-        _dataForTesting = _loader.dataForTesting;
+        _dataForTesting = _loader.dataForTesting,
+        useNewMethodInvocationEncoding =
+            _loader.target.backendTarget.supportsNewMethodInvocationEncoding {
+    _listAddFunctionType = _listAdd.getterType;
+    _listAddAllFunctionType = _listAddAll.getterType;
+    _setAddFunctionType = _setAdd.getterType;
+    _setAddAllFunctionType = _setAddAll.getterType;
+    _mapPutFunctionType = _mapPut.getterType;
+  }
 
   TreeNode _translateListOrSet(
       Expression node, DartType elementType, List<Expression> elements,
@@ -139,6 +118,9 @@
     // If there were only expressions, we are done.
     if (index == elements.length) return node;
 
+    InterfaceType receiverType = isSet
+        ? _typeEnvironment.setType(elementType, _currentLibrary.nonNullable)
+        : _typeEnvironment.listType(elementType, _currentLibrary.nonNullable);
     VariableDeclaration result;
     if (index == 0 && elements[index] is SpreadElement) {
       SpreadElement initialSpread = elements[index];
@@ -156,8 +138,7 @@
                   new Arguments([value], types: [elementType])
                     ..fileOffset = node.fileOffset)
                 ..fileOffset = node.fileOffset,
-              _typeEnvironment.setType(
-                  elementType, _currentLibrary.nonNullable));
+              receiverType);
         } else {
           result = _createVariable(
               new StaticInvocation(
@@ -165,8 +146,7 @@
                   new Arguments([value], types: [elementType])
                     ..fileOffset = node.fileOffset)
                 ..fileOffset = node.fileOffset,
-              _typeEnvironment.listType(
-                  elementType, _currentLibrary.nonNullable));
+              receiverType);
         }
       }
     }
@@ -180,8 +160,7 @@
           result = _createVariable(
               _createSetLiteral(
                   node.fileOffset, elementType, elements.sublist(0, index)),
-              _typeEnvironment.setType(
-                  elementType, _currentLibrary.nonNullable));
+              receiverType);
         } else {
           // TODO(johnniwinther): When all the back ends handle set literals we
           //  can use remove this branch.
@@ -193,12 +172,12 @@
                   new Arguments([], types: [elementType])
                     ..fileOffset = node.fileOffset)
                 ..fileOffset = node.fileOffset,
-              _typeEnvironment.setType(
-                  elementType, _currentLibrary.nonNullable));
+              receiverType);
           body = [result];
           // Add the elements up to the first non-expression.
           for (int j = 0; j < index; ++j) {
-            _addExpressionElement(elements[j], isSet, result, body);
+            _addExpressionElement(
+                elements[j], receiverType, isSet, result, body);
           }
         }
       } else {
@@ -207,50 +186,65 @@
         result = _createVariable(
             _createListLiteral(
                 node.fileOffset, elementType, elements.sublist(0, index)),
-            _typeEnvironment.listType(
-                elementType, _currentLibrary.nonNullable));
+            receiverType);
       }
     }
     body ??= [result];
     // Translate the elements starting with the first non-expression.
     for (; index < elements.length; ++index) {
-      _translateElement(elements[index], elementType, isSet, result, body);
+      _translateElement(
+          elements[index], receiverType, elementType, isSet, result, body);
     }
 
     return _createBlockExpression(
         node.fileOffset, _createBlock(body), _createVariableGet(result));
   }
 
-  void _translateElement(Expression element, DartType elementType, bool isSet,
-      VariableDeclaration result, List<Statement> body) {
+  void _translateElement(
+      Expression element,
+      InterfaceType receiverType,
+      DartType elementType,
+      bool isSet,
+      VariableDeclaration result,
+      List<Statement> body) {
     if (element is SpreadElement) {
-      _translateSpreadElement(element, elementType, isSet, result, body);
+      _translateSpreadElement(
+          element, receiverType, elementType, isSet, result, body);
     } else if (element is IfElement) {
-      _translateIfElement(element, elementType, isSet, result, body);
+      _translateIfElement(
+          element, receiverType, elementType, isSet, result, body);
     } else if (element is ForElement) {
-      _translateForElement(element, elementType, isSet, result, body);
+      _translateForElement(
+          element, receiverType, elementType, isSet, result, body);
     } else if (element is ForInElement) {
-      _translateForInElement(element, elementType, isSet, result, body);
+      _translateForInElement(
+          element, receiverType, elementType, isSet, result, body);
     } else {
       _addExpressionElement(
-          element.accept<TreeNode>(this), isSet, result, body);
+          element.accept<TreeNode>(this), receiverType, isSet, result, body);
     }
   }
 
-  void _addExpressionElement(Expression element, bool isSet,
-      VariableDeclaration result, List<Statement> body) {
+  void _addExpressionElement(Expression element, InterfaceType receiverType,
+      bool isSet, VariableDeclaration result, List<Statement> body) {
     body.add(_createExpressionStatement(
-        _createAdd(_createVariableGet(result), element, isSet)));
+        _createAdd(_createVariableGet(result), receiverType, element, isSet)));
   }
 
-  void _translateIfElement(IfElement element, DartType elementType, bool isSet,
-      VariableDeclaration result, List<Statement> body) {
+  void _translateIfElement(
+      IfElement element,
+      InterfaceType receiverType,
+      DartType elementType,
+      bool isSet,
+      VariableDeclaration result,
+      List<Statement> body) {
     List<Statement> thenStatements = [];
-    _translateElement(element.then, elementType, isSet, result, thenStatements);
+    _translateElement(
+        element.then, receiverType, elementType, isSet, result, thenStatements);
     List<Statement> elseStatements;
     if (element.otherwise != null) {
-      _translateElement(element.otherwise, elementType, isSet, result,
-          elseStatements = <Statement>[]);
+      _translateElement(element.otherwise, receiverType, elementType, isSet,
+          result, elseStatements = <Statement>[]);
     }
     Statement thenBody = thenStatements.length == 1
         ? thenStatements.first
@@ -265,10 +259,16 @@
         element.condition.accept<TreeNode>(this), thenBody, elseBody));
   }
 
-  void _translateForElement(ForElement element, DartType elementType,
-      bool isSet, VariableDeclaration result, List<Statement> body) {
+  void _translateForElement(
+      ForElement element,
+      InterfaceType receiverType,
+      DartType elementType,
+      bool isSet,
+      VariableDeclaration result,
+      List<Statement> body) {
     List<Statement> statements = <Statement>[];
-    _translateElement(element.body, elementType, isSet, result, statements);
+    _translateElement(
+        element.body, receiverType, elementType, isSet, result, statements);
     Statement loopBody =
         statements.length == 1 ? statements.first : _createBlock(statements);
     ForStatement loop = _createForStatement(
@@ -283,8 +283,13 @@
     body.add(loop);
   }
 
-  void _translateForInElement(ForInElement element, DartType elementType,
-      bool isSet, VariableDeclaration result, List<Statement> body) {
+  void _translateForInElement(
+      ForInElement element,
+      InterfaceType receiverType,
+      DartType elementType,
+      bool isSet,
+      VariableDeclaration result,
+      List<Statement> body) {
     List<Statement> statements;
     Statement prologue = element.prologue;
     if (prologue == null) {
@@ -294,7 +299,8 @@
       statements =
           prologue is Block ? prologue.statements : <Statement>[prologue];
     }
-    _translateElement(element.body, elementType, isSet, result, statements);
+    _translateElement(
+        element.body, receiverType, elementType, isSet, result, statements);
     Statement loopBody =
         statements.length == 1 ? statements.first : _createBlock(statements);
     if (element.problem != null) {
@@ -308,8 +314,13 @@
     body.add(loop);
   }
 
-  void _translateSpreadElement(SpreadElement element, DartType elementType,
-      bool isSet, VariableDeclaration result, List<Statement> body) {
+  void _translateSpreadElement(
+      SpreadElement element,
+      InterfaceType receiverType,
+      DartType elementType,
+      bool isSet,
+      VariableDeclaration result,
+      List<Statement> body) {
     Expression value = element.expression.accept<TreeNode>(this);
 
     final bool typeMatches = element.elementType != null &&
@@ -331,8 +342,8 @@
         value = _createNullCheckedVariableGet(temp);
       }
 
-      Statement statement = _createExpressionStatement(
-          _createAddAll(_createVariableGet(result), value, isSet));
+      Statement statement = _createExpressionStatement(_createAddAll(
+          _createVariableGet(result), receiverType, value, isSet));
 
       if (element.isNullAware) {
         statement = _createIf(
@@ -365,13 +376,16 @@
             elementType);
         loopBody = _createBlock(<Statement>[
           castedVar,
-          _createExpressionStatement(_createAdd(
-              _createVariableGet(result), _createVariableGet(castedVar), isSet))
+          _createExpressionStatement(_createAdd(_createVariableGet(result),
+              receiverType, _createVariableGet(castedVar), isSet))
         ]);
       } else {
         variable = _createForInVariable(element.fileOffset, elementType);
         loopBody = _createExpressionStatement(_createAdd(
-            _createVariableGet(result), _createVariableGet(variable), isSet));
+            _createVariableGet(result),
+            receiverType,
+            _createVariableGet(variable),
+            isSet));
       }
       Statement statement =
           _createForInStatement(element.fileOffset, variable, value, loopBody);
@@ -425,52 +439,66 @@
     if (i == node.entries.length) return node;
 
     // Build a block expression and create an empty map.
+    InterfaceType receiverType = _typeEnvironment.mapType(
+        node.keyType, node.valueType, _currentLibrary.nonNullable);
     VariableDeclaration result = _createVariable(
         _createMapLiteral(node.fileOffset, node.keyType, node.valueType, []),
-        _typeEnvironment.mapType(
-            node.keyType, node.valueType, _currentLibrary.nonNullable));
+        receiverType);
     List<Statement> body = [result];
     // Add all the entries up to the first control-flow entry.
     for (int j = 0; j < i; ++j) {
-      _addNormalEntry(node.entries[j], result, body);
+      _addNormalEntry(node.entries[j], receiverType, result, body);
     }
     for (; i < node.entries.length; ++i) {
-      _translateEntry(
-          node.entries[i], node.keyType, node.valueType, result, body);
+      _translateEntry(node.entries[i], receiverType, node.keyType,
+          node.valueType, result, body);
     }
 
     return _createBlockExpression(
         node.fileOffset, _createBlock(body), _createVariableGet(result));
   }
 
-  void _translateEntry(MapEntry entry, DartType keyType, DartType valueType,
-      VariableDeclaration result, List<Statement> body) {
+  void _translateEntry(
+      MapEntry entry,
+      InterfaceType receiverType,
+      DartType keyType,
+      DartType valueType,
+      VariableDeclaration result,
+      List<Statement> body) {
     if (entry is SpreadMapEntry) {
-      _translateSpreadEntry(entry, keyType, valueType, result, body);
+      _translateSpreadEntry(
+          entry, receiverType, keyType, valueType, result, body);
     } else if (entry is IfMapEntry) {
-      _translateIfEntry(entry, keyType, valueType, result, body);
+      _translateIfEntry(entry, receiverType, keyType, valueType, result, body);
     } else if (entry is ForMapEntry) {
-      _translateForEntry(entry, keyType, valueType, result, body);
+      _translateForEntry(entry, receiverType, keyType, valueType, result, body);
     } else if (entry is ForInMapEntry) {
-      _translateForInEntry(entry, keyType, valueType, result, body);
+      _translateForInEntry(
+          entry, receiverType, keyType, valueType, result, body);
     } else {
-      _addNormalEntry(entry.accept<TreeNode>(this), result, body);
+      _addNormalEntry(entry.accept<TreeNode>(this), receiverType, result, body);
     }
   }
 
-  void _addNormalEntry(
-      MapEntry entry, VariableDeclaration result, List<Statement> body) {
-    body.add(_createExpressionStatement(_createIndexSet(
-        entry.fileOffset, _createVariableGet(result), entry.key, entry.value)));
+  void _addNormalEntry(MapEntry entry, InterfaceType receiverType,
+      VariableDeclaration result, List<Statement> body) {
+    body.add(_createExpressionStatement(_createIndexSet(entry.fileOffset,
+        _createVariableGet(result), receiverType, entry.key, entry.value)));
   }
 
-  void _translateIfEntry(IfMapEntry entry, DartType keyType, DartType valueType,
-      VariableDeclaration result, List<Statement> body) {
+  void _translateIfEntry(
+      IfMapEntry entry,
+      InterfaceType receiverType,
+      DartType keyType,
+      DartType valueType,
+      VariableDeclaration result,
+      List<Statement> body) {
     List<Statement> thenBody = [];
-    _translateEntry(entry.then, keyType, valueType, result, thenBody);
+    _translateEntry(
+        entry.then, receiverType, keyType, valueType, result, thenBody);
     List<Statement> elseBody;
     if (entry.otherwise != null) {
-      _translateEntry(entry.otherwise, keyType, valueType, result,
+      _translateEntry(entry.otherwise, receiverType, keyType, valueType, result,
           elseBody = <Statement>[]);
     }
     Statement thenStatement =
@@ -484,10 +512,16 @@
         thenStatement, elseStatement));
   }
 
-  void _translateForEntry(ForMapEntry entry, DartType keyType,
-      DartType valueType, VariableDeclaration result, List<Statement> body) {
+  void _translateForEntry(
+      ForMapEntry entry,
+      InterfaceType receiverType,
+      DartType keyType,
+      DartType valueType,
+      VariableDeclaration result,
+      List<Statement> body) {
     List<Statement> statements = <Statement>[];
-    _translateEntry(entry.body, keyType, valueType, result, statements);
+    _translateEntry(
+        entry.body, receiverType, keyType, valueType, result, statements);
     Statement loopBody =
         statements.length == 1 ? statements.first : _createBlock(statements);
     ForStatement loop = _createForStatement(entry.fileOffset, entry.variables,
@@ -498,8 +532,13 @@
     body.add(loop);
   }
 
-  void _translateForInEntry(ForInMapEntry entry, DartType keyType,
-      DartType valueType, VariableDeclaration result, List<Statement> body) {
+  void _translateForInEntry(
+      ForInMapEntry entry,
+      InterfaceType receiverType,
+      DartType keyType,
+      DartType valueType,
+      VariableDeclaration result,
+      List<Statement> body) {
     List<Statement> statements;
     Statement prologue = entry.prologue;
     if (prologue == null) {
@@ -509,7 +548,8 @@
       statements =
           prologue is Block ? prologue.statements : <Statement>[prologue];
     }
-    _translateEntry(entry.body, keyType, valueType, result, statements);
+    _translateEntry(
+        entry.body, receiverType, keyType, valueType, result, statements);
     Statement loopBody =
         statements.length == 1 ? statements.first : _createBlock(statements);
     if (entry.problem != null) {
@@ -523,8 +563,13 @@
     body.add(loop);
   }
 
-  void _translateSpreadEntry(SpreadMapEntry entry, DartType keyType,
-      DartType valueType, VariableDeclaration result, List<Statement> body) {
+  void _translateSpreadEntry(
+      SpreadMapEntry entry,
+      InterfaceType receiverType,
+      DartType keyType,
+      DartType valueType,
+      VariableDeclaration result,
+      List<Statement> body) {
     Expression value = entry.expression.accept<TreeNode>(this);
 
     final DartType entryType = new InterfaceType(_mapEntryClass,
@@ -573,6 +618,7 @@
         _createExpressionStatement(_createIndexSet(
             entry.expression.fileOffset,
             _createVariableGet(result),
+            receiverType,
             _createVariableGet(keyVar),
             _createVariableGet(valueVar)))
       ]);
@@ -581,6 +627,7 @@
       loopBody = _createExpressionStatement(_createIndexSet(
           entry.expression.fileOffset,
           _createVariableGet(result),
+          receiverType,
           _createGetKey(
               entry.expression.fileOffset, _createVariableGet(variable)),
           _createGetValue(
@@ -839,53 +886,101 @@
       ..fileOffset = expression.fileOffset;
   }
 
-  MethodInvocation _createAdd(
-      Expression receiver, Expression argument, bool isSet) {
+  Expression _createAdd(Expression receiver, InterfaceType receiverType,
+      Expression argument, bool isSet) {
     assert(receiver != null);
     assert(argument != null);
     assert(argument.fileOffset != TreeNode.noOffset,
         "No fileOffset on ${argument}.");
-    return new MethodInvocation(receiver, new Name('add'),
-        new Arguments([argument]), isSet ? _setAdd : _listAdd)
-      ..fileOffset = argument.fileOffset
-      ..isInvariant = true;
+    if (useNewMethodInvocationEncoding) {
+      FunctionType functionType = Substitution.fromInterfaceType(receiverType)
+          .substituteType(isSet ? _setAddFunctionType : _listAddFunctionType);
+      if (!_currentLibrary.isNonNullableByDefault) {
+        functionType = legacyErasure(functionType);
+      }
+      return new InstanceInvocation(InstanceAccessKind.Instance, receiver,
+          new Name('add'), new Arguments([argument]),
+          functionType: functionType,
+          interfaceTarget: isSet ? _setAdd : _listAdd)
+        ..fileOffset = argument.fileOffset
+        ..isInvariant = true;
+    } else {
+      return new MethodInvocation(receiver, new Name('add'),
+          new Arguments([argument]), isSet ? _setAdd : _listAdd)
+        ..fileOffset = argument.fileOffset
+        ..isInvariant = true;
+    }
   }
 
-  MethodInvocation _createAddAll(
-      Expression receiver, Expression argument, bool isSet) {
+  Expression _createAddAll(Expression receiver, InterfaceType receiverType,
+      Expression argument, bool isSet) {
     assert(receiver != null);
     assert(argument != null);
     assert(argument.fileOffset != TreeNode.noOffset,
         "No fileOffset on ${argument}.");
-    return new MethodInvocation(receiver, new Name('addAll'),
-        new Arguments([argument]), isSet ? _setAddAll : _listAddAll)
-      ..fileOffset = argument.fileOffset
-      ..isInvariant = true;
+    if (useNewMethodInvocationEncoding) {
+      FunctionType functionType = Substitution.fromInterfaceType(receiverType)
+          .substituteType(
+              isSet ? _setAddAllFunctionType : _listAddAllFunctionType);
+      if (!_currentLibrary.isNonNullableByDefault) {
+        functionType = legacyErasure(functionType);
+      }
+      return new InstanceInvocation(InstanceAccessKind.Instance, receiver,
+          new Name('addAll'), new Arguments([argument]),
+          functionType: functionType,
+          interfaceTarget: isSet ? _setAddAll : _listAddAll)
+        ..fileOffset = argument.fileOffset
+        ..isInvariant = true;
+    } else {
+      return new MethodInvocation(receiver, new Name('addAll'),
+          new Arguments([argument]), isSet ? _setAddAll : _listAddAll)
+        ..fileOffset = argument.fileOffset
+        ..isInvariant = true;
+    }
   }
 
   Expression _createEqualsNull(Expression expression, {bool notEquals: false}) {
     assert(expression != null);
     assert(expression.fileOffset != TreeNode.noOffset);
-    Expression check = new MethodInvocation(
-        expression,
-        new Name('=='),
-        new Arguments([new NullLiteral()..fileOffset = expression.fileOffset]),
-        _objectEquals)
-      ..fileOffset = expression.fileOffset;
-    if (notEquals) {
-      check = new Not(check)..fileOffset = expression.fileOffset;
+    if (useNewMethodInvocationEncoding) {
+      return new EqualsNull(expression, isNot: notEquals)
+        ..fileOffset = expression.fileOffset;
+    } else {
+      Expression check = new MethodInvocation(
+          expression,
+          new Name('=='),
+          new Arguments(
+              [new NullLiteral()..fileOffset = expression.fileOffset]),
+          _objectEquals)
+        ..fileOffset = expression.fileOffset;
+      if (notEquals) {
+        check = new Not(check)..fileOffset = expression.fileOffset;
+      }
+      return check;
     }
-    return check;
   }
 
-  MethodInvocation _createIndexSet(
-      int fileOffset, Expression receiver, Expression key, Expression value) {
+  Expression _createIndexSet(int fileOffset, Expression receiver,
+      InterfaceType receiverType, Expression key, Expression value) {
     assert(fileOffset != null);
     assert(fileOffset != TreeNode.noOffset);
-    return new MethodInvocation(
-        receiver, new Name('[]='), new Arguments([key, value]), _mapPut)
-      ..fileOffset = fileOffset
-      ..isInvariant = true;
+    if (useNewMethodInvocationEncoding) {
+      FunctionType functionType = Substitution.fromInterfaceType(receiverType)
+          .substituteType(_mapPutFunctionType);
+      if (!_currentLibrary.isNonNullableByDefault) {
+        functionType = legacyErasure(functionType);
+      }
+      return new InstanceInvocation(InstanceAccessKind.Instance, receiver,
+          new Name('[]='), new Arguments([key, value]),
+          functionType: functionType, interfaceTarget: _mapPut)
+        ..fileOffset = fileOffset
+        ..isInvariant = true;
+    } else {
+      return new MethodInvocation(
+          receiver, new Name('[]='), new Arguments([key, value]), _mapPut)
+        ..fileOffset = fileOffset
+        ..isInvariant = true;
+    }
   }
 
   AsExpression _createImplicitAs(
diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart b/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
index 67f0898..e9d5969 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
@@ -6,27 +6,14 @@
 
 import 'dart:core' hide MapEntry;
 
-import 'package:kernel/ast.dart'
-    show
-        Arguments,
-        Block,
-        BlockExpression,
-        Expression,
-        ExpressionStatement,
-        InterfaceType,
-        Library,
-        MethodInvocation,
-        Name,
-        Procedure,
-        SetLiteral,
-        Statement,
-        StaticInvocation,
-        TreeNode,
-        VariableDeclaration,
-        VariableGet;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/core_types.dart' show CoreTypes;
 
+import 'package:kernel/src/legacy_erasure.dart' show legacyErasure;
+
+import 'package:kernel/type_algebra.dart' show Substitution;
+
 import 'package:kernel/visitor.dart' show Transformer;
 
 import '../source/source_loader.dart' show SourceLoader;
@@ -38,6 +25,8 @@
   final CoreTypes coreTypes;
   final Procedure setFactory;
   final Procedure addMethod;
+  FunctionType _addMethodFunctionType;
+  final bool useNewMethodInvocationEncoding;
 
   /// Library that contains the transformed nodes.
   ///
@@ -58,29 +47,45 @@
   SetLiteralTransformer(SourceLoader loader)
       : coreTypes = loader.coreTypes,
         setFactory = _findSetFactory(loader.coreTypes),
-        addMethod = _findAddMethod(loader.coreTypes);
+        addMethod = _findAddMethod(loader.coreTypes),
+        useNewMethodInvocationEncoding =
+            loader.target.backendTarget.supportsNewMethodInvocationEncoding {
+    _addMethodFunctionType = addMethod.getterType;
+  }
 
   TreeNode visitSetLiteral(SetLiteral node) {
     if (node.isConst) return node;
 
     // Create the set: Set<E> setVar = new Set<E>();
+    DartType receiverType;
     VariableDeclaration setVar = new VariableDeclaration.forValue(
         new StaticInvocation(
             setFactory, new Arguments([], types: [node.typeArgument])),
-        type: new InterfaceType(coreTypes.setClass, _currentLibrary.nonNullable,
-            [node.typeArgument]));
+        type: receiverType = new InterfaceType(coreTypes.setClass,
+            _currentLibrary.nonNullable, [node.typeArgument]));
 
     // Now create a list of all statements needed.
     List<Statement> statements = [setVar];
     for (int i = 0; i < node.expressions.length; i++) {
       Expression entry = node.expressions[i].accept<TreeNode>(this);
-      MethodInvocation methodInvocation = new MethodInvocation(
-          new VariableGet(setVar),
-          new Name("add"),
-          new Arguments([entry]),
-          addMethod)
-        ..fileOffset = entry.fileOffset
-        ..isInvariant = true;
+      Expression methodInvocation;
+      if (useNewMethodInvocationEncoding) {
+        FunctionType functionType = Substitution.fromInterfaceType(receiverType)
+            .substituteType(_addMethodFunctionType);
+        if (!_currentLibrary.isNonNullableByDefault) {
+          functionType = legacyErasure(functionType);
+        }
+        methodInvocation = new InstanceInvocation(InstanceAccessKind.Instance,
+            new VariableGet(setVar), new Name("add"), new Arguments([entry]),
+            functionType: functionType, interfaceTarget: addMethod)
+          ..fileOffset = entry.fileOffset
+          ..isInvariant = true;
+      } else {
+        methodInvocation = new MethodInvocation(new VariableGet(setVar),
+            new Name("add"), new Arguments([entry]), addMethod)
+          ..fileOffset = entry.fileOffset
+          ..isInvariant = true;
+      }
       statements.add(new ExpressionStatement(methodInvocation)
         ..fileOffset = methodInvocation.fileOffset);
     }
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index b2645dd..54f9683 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -811,9 +811,19 @@
         new Arguments.forwarded(procedure.function, library.library),
         procedure.fileOffset,
         /*isSuper=*/ false);
-    Expression result = new MethodInvocation(new ThisExpression(),
-        noSuchMethodName, new Arguments([invocation]), noSuchMethodInterface)
-      ..fileOffset = procedure.fileOffset;
+    Expression result;
+    if (library
+        .loader.target.backendTarget.supportsNewMethodInvocationEncoding) {
+      result = new InstanceInvocation(InstanceAccessKind.Instance,
+          new ThisExpression(), noSuchMethodName, new Arguments([invocation]),
+          functionType: noSuchMethodInterface.getterType,
+          interfaceTarget: noSuchMethodInterface)
+        ..fileOffset = procedure.fileOffset;
+    } else {
+      result = new MethodInvocation(new ThisExpression(), noSuchMethodName,
+          new Arguments([invocation]), noSuchMethodInterface)
+        ..fileOffset = procedure.fileOffset;
+    }
     if (procedure.function.returnType is! VoidType) {
       result = new AsExpression(result, procedure.function.returnType)
         ..isTypeError = true
diff --git a/pkg/front_end/lib/src/fasta/source/stack_listener_impl.dart b/pkg/front_end/lib/src/fasta/source/stack_listener_impl.dart
index f3af4a5..543eaa4 100644
--- a/pkg/front_end/lib/src/fasta/source/stack_listener_impl.dart
+++ b/pkg/front_end/lib/src/fasta/source/stack_listener_impl.dart
@@ -77,7 +77,7 @@
   }
 
   /// Used to report an internal error encountered in the stack listener.
-  dynamic internalProblem(Message message, int charOffset, Uri uri) {
+  internalProblem(Message message, int charOffset, Uri uri) {
     return problems.internalProblem(message, charOffset, uri);
   }
 
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index addccd7..a673e21 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -238,6 +238,9 @@
 
   NnbdMode get nnbdMode => library.loader.nnbdMode;
 
+  bool get useNewMethodInvocationEncoding =>
+      library.loader.target.backendTarget.supportsNewMethodInvocationEncoding;
+
   DartType get bottomType => isNonNullableByDefault
       ? const NeverType(Nullability.nonNullable)
       : const NullType();
@@ -677,9 +680,20 @@
     VariableDeclaration t =
         new VariableDeclaration.forValue(expression, type: expressionType)
           ..fileOffset = fileOffset;
-    Expression nullCheck = new MethodInvocation(new VariableGet(t), equalsName,
-        new Arguments(<Expression>[new NullLiteral()..fileOffset = fileOffset]))
-      ..fileOffset = fileOffset;
+    Expression nullCheck;
+    // TODO(johnniwinther): Avoid null-check for non-nullable expressions.
+    if (useNewMethodInvocationEncoding) {
+      nullCheck = new EqualsNull(new VariableGet(t)..fileOffset = fileOffset,
+          isNot: false)
+        ..fileOffset = fileOffset;
+    } else {
+      nullCheck = new MethodInvocation(
+          new VariableGet(t)..fileOffset = fileOffset,
+          equalsName,
+          new Arguments(
+              <Expression>[new NullLiteral()..fileOffset = fileOffset]))
+        ..fileOffset = fileOffset;
+    }
     PropertyGet tearOff =
         new PropertyGet(new VariableGet(t), callName, callMember)
           ..fileOffset = fileOffset;
@@ -989,10 +1003,9 @@
       Member member =
           _getInterfaceMember(coreTypes.objectClass, name, setter, fileOffset);
       if (member != null) {
-        return new ObjectAccessTarget.interfaceMember(member,
-            // Null implements all Object members so this is not considered a
-            // potentially nullable access.
-            isPotentiallyNullable: false);
+        // Null implements all Object members so this is not considered a
+        // potentially nullable access.
+        return new ObjectAccessTarget.objectMember(member);
       }
       if (includeExtensionMethods && receiverBound is! DynamicType) {
         ObjectAccessTarget target = _findExtensionMember(
@@ -1051,7 +1064,7 @@
     }
     if (instrumented &&
         receiverBound != const DynamicType() &&
-        target.isInstanceMember) {
+        (target.isInstanceMember || target.isObjectMember)) {
       instrumentation?.record(uriForInstrumentation, fileOffset, 'target',
           new InstrumentationValueForMember(target.member));
     }
@@ -1139,6 +1152,7 @@
       case ObjectAccessTargetKind.never:
         return const NeverType(Nullability.nonNullable);
       case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
       case ObjectAccessTargetKind.nullableInstanceMember:
         return getGetterTypeForMemberTarget(target.member, receiverType);
       case ObjectAccessTargetKind.extensionMember:
@@ -1246,6 +1260,7 @@
       case ObjectAccessTargetKind.ambiguous:
         return unknownFunction;
       case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
       case ObjectAccessTargetKind.nullableInstanceMember:
         return _getFunctionType(
             getGetterTypeForMemberTarget(target.member, receiverType));
@@ -1286,6 +1301,7 @@
   DartType getReturnType(ObjectAccessTarget target, DartType receiverType) {
     switch (target.kind) {
       case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
       case ObjectAccessTargetKind.nullableInstanceMember:
         FunctionType functionType = _getFunctionType(
             getGetterTypeForMemberTarget(target.member, receiverType));
@@ -1327,6 +1343,7 @@
       ObjectAccessTarget target, DartType receiverType, int index) {
     switch (target.kind) {
       case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
       case ObjectAccessTargetKind.nullableInstanceMember:
         FunctionType functionType = _getFunctionType(
             getGetterTypeForMemberTarget(target.member, receiverType));
@@ -1384,6 +1401,7 @@
   DartType getIndexKeyType(ObjectAccessTarget target, DartType receiverType) {
     switch (target.kind) {
       case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
       case ObjectAccessTargetKind.nullableInstanceMember:
         FunctionType functionType = _getFunctionType(
             getGetterTypeForMemberTarget(target.member, receiverType));
@@ -1444,6 +1462,7 @@
       ObjectAccessTarget target, DartType receiverType) {
     switch (target.kind) {
       case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
       case ObjectAccessTargetKind.nullableInstanceMember:
         FunctionType functionType = _getFunctionType(
             getGetterTypeForMemberTarget(target.member, receiverType));
@@ -1540,6 +1559,7 @@
       case ObjectAccessTargetKind.invalid:
         return const InvalidType();
       case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
       case ObjectAccessTargetKind.nullableInstanceMember:
         Member interfaceMember = target.member;
         Class memberClass = interfaceMember.enclosingClass;
@@ -2173,10 +2193,12 @@
       if (argMessage != null) {
         return new WrapInProblemInferenceResult(
             const InvalidType(),
+            const InvalidType(),
             argMessage.messageObject,
             argMessage.charOffset,
             argMessage.length,
-            helper);
+            helper,
+            isInapplicable: true);
       } else {
         // Argument counts and names match. Compare types.
         int positionalShift = isImplicitExtensionMember ? 1 : 0;
@@ -2233,9 +2255,10 @@
 
     if (!isNonNullableByDefault) {
       inferredType = legacyErasure(inferredType);
+      calleeType = legacyErasure(calleeType);
     }
 
-    return new SuccessfulInferenceResult(inferredType);
+    return new SuccessfulInferenceResult(inferredType, calleeType);
   }
 
   DartType inferLocalFunction(FunctionNode function, DartType typeContext,
@@ -2488,11 +2511,17 @@
         receiverType: const DynamicType(),
         isImplicitCall: isImplicitCall);
     assert(name != equalsName);
+    Expression expression;
+    if (useNewMethodInvocationEncoding) {
+      expression = new DynamicInvocation(
+          DynamicAccessKind.Dynamic, receiver, name, arguments)
+        ..fileOffset = fileOffset;
+    } else {
+      expression = new MethodInvocation(receiver, name, arguments)
+        ..fileOffset = fileOffset;
+    }
     return createNullAwareExpressionInferenceResult(
-        result.inferredType,
-        result.applyResult(new MethodInvocation(receiver, name, arguments)
-          ..fileOffset = fileOffset),
-        nullAwareGuards);
+        result.inferredType, result.applyResult(expression), nullAwareGuards);
   }
 
   ExpressionInferenceResult _inferNeverInvocation(
@@ -2512,10 +2541,18 @@
         receiverType: receiverType,
         isImplicitCall: isImplicitCall);
     assert(name != equalsName);
+    Expression expression;
+    if (useNewMethodInvocationEncoding) {
+      expression = new DynamicInvocation(
+          DynamicAccessKind.Never, receiver, name, arguments)
+        ..fileOffset = fileOffset;
+    } else {
+      expression = new MethodInvocation(receiver, name, arguments)
+        ..fileOffset = fileOffset;
+    }
     return createNullAwareExpressionInferenceResult(
         const NeverType(Nullability.nonNullable),
-        result.applyResult(new MethodInvocation(receiver, name, arguments)
-          ..fileOffset = fileOffset),
+        result.applyResult(expression),
         nullAwareGuards);
   }
 
@@ -2642,15 +2679,49 @@
       {bool isImplicitCall}) {
     assert(isImplicitCall != null);
     assert(target.isCallFunction || target.isNullableCallFunction);
-    FunctionType functionType = getFunctionType(target, receiverType);
+    FunctionType declaredFunctionType = getFunctionType(target, receiverType);
     InvocationInferenceResult result = inferInvocation(
-        typeContext, fileOffset, functionType, arguments,
+        typeContext, fileOffset, declaredFunctionType, arguments,
         hoistedExpressions: hoistedExpressions,
         receiverType: receiverType,
         isImplicitCall: isImplicitCall);
-    Expression replacement = result.applyResult(
-        new MethodInvocation(receiver, callName, arguments)
-          ..fileOffset = fileOffset);
+    Expression expression;
+    if (useNewMethodInvocationEncoding) {
+      DartType inferredFunctionType = result.functionType;
+      if (result.isInapplicable) {
+        // This was a function invocation whose arguments didn't match
+        // the parameters.
+        expression = new FunctionInvocation(
+            FunctionAccessKind.Inapplicable, receiver, arguments,
+            functionType: null)
+          ..fileOffset = fileOffset;
+      } else if (receiver is VariableGet) {
+        VariableDeclaration variable = receiver.variable;
+        if (variable.parent is FunctionDeclaration) {
+          assert(inferredFunctionType != unknownFunction,
+              "Unknown function type for local function invocation.");
+          expression = new LocalFunctionInvocation(variable, arguments,
+              functionType: inferredFunctionType)
+            ..fileOffset = receiver.fileOffset;
+        }
+      }
+      expression ??= new FunctionInvocation(
+          target.isNullableCallFunction
+              ? FunctionAccessKind.Nullable
+              : (inferredFunctionType == unknownFunction
+                  ? FunctionAccessKind.Function
+                  : FunctionAccessKind.FunctionType),
+          receiver,
+          arguments,
+          functionType: inferredFunctionType == unknownFunction
+              ? null
+              : inferredFunctionType)
+        ..fileOffset = fileOffset;
+    } else {
+      expression = new MethodInvocation(receiver, callName, arguments)
+        ..fileOffset = fileOffset;
+    }
+    Expression replacement = result.applyResult(expression);
     if (!isTopLevel && target.isNullableCallFunction) {
       if (isImplicitCall) {
         replacement = helper.wrapInProblem(
@@ -2673,6 +2744,16 @@
         result.inferredType, replacement, nullAwareGuards);
   }
 
+  FunctionType _computeFunctionTypeForArguments(
+      Arguments arguments, DartType type) {
+    return new FunctionType(
+        new List<DartType>.filled(arguments.positional.length, type),
+        type,
+        library.nonNullable,
+        namedParameters: new List<NamedType>.generate(arguments.named.length,
+            (int index) => new NamedType(arguments.named[index].name, type)));
+  }
+
   ExpressionInferenceResult _inferInstanceMethodInvocation(
       int fileOffset,
       Link<NullAwareGuard> nullAwareGuards,
@@ -2688,7 +2769,9 @@
     assert(isImplicitCall != null);
     assert(isSpecialCasedBinaryOperator != null);
     assert(isSpecialCasedTernaryOperator != null);
-    assert(target.isInstanceMember || target.isNullableInstanceMember);
+    assert(target.isInstanceMember ||
+        target.isObjectMember ||
+        target.isNullableInstanceMember);
     Procedure method = target.member;
     assert(method.kind == ProcedureKind.Method,
         "Unexpected instance method $method");
@@ -2715,7 +2798,7 @@
     }
 
     DartType calleeType = getGetterType(target, receiverType);
-    FunctionType functionType = getFunctionType(target, receiverType);
+    FunctionType declaredFunctionType = getFunctionType(target, receiverType);
 
     bool contravariantCheck = false;
     if (receiver is! ThisExpression &&
@@ -2725,20 +2808,64 @@
       contravariantCheck = true;
     }
     InvocationInferenceResult result = inferInvocation(
-        typeContext, fileOffset, functionType, arguments,
+        typeContext, fileOffset, declaredFunctionType, arguments,
         hoistedExpressions: hoistedExpressions,
         receiverType: receiverType,
         isImplicitCall: isImplicitCall,
         isSpecialCasedBinaryOperator: isSpecialCasedBinaryOperator,
         isSpecialCasedTernaryOperator: isSpecialCasedTernaryOperator);
 
+    Expression expression;
+    if (useNewMethodInvocationEncoding) {
+      DartType inferredFunctionType = result.functionType;
+      if (target.isDynamic) {
+        // This was an Object member invocation whose arguments didn't match
+        // the parameters.
+        expression = new DynamicInvocation(
+            DynamicAccessKind.Dynamic, receiver, methodName, arguments)
+          ..fileOffset = fileOffset;
+      } else if (result.isInapplicable) {
+        // This was a method invocation whose arguments didn't match
+        // the parameters.
+        expression = new InstanceInvocation(
+            InstanceAccessKind.Inapplicable, receiver, methodName, arguments,
+            functionType: _computeFunctionTypeForArguments(
+                arguments, const InvalidType()),
+            interfaceTarget: method)
+          ..fileOffset = fileOffset;
+      } else {
+        assert(
+            inferredFunctionType is FunctionType &&
+                !identical(unknownFunction, inferredFunctionType),
+            "No function type found for $receiver.$methodName ($target) on "
+            "$receiverType");
+        InstanceAccessKind kind;
+        switch (target.kind) {
+          case ObjectAccessTargetKind.instanceMember:
+            kind = InstanceAccessKind.Instance;
+            break;
+          case ObjectAccessTargetKind.nullableInstanceMember:
+            kind = InstanceAccessKind.Nullable;
+            break;
+          case ObjectAccessTargetKind.objectMember:
+            kind = InstanceAccessKind.Object;
+            break;
+          default:
+            throw new UnsupportedError('Unexpected target kind $target');
+        }
+        expression = new InstanceInvocation(
+            kind, receiver, methodName, arguments,
+            functionType: inferredFunctionType, interfaceTarget: method)
+          ..fileOffset = fileOffset;
+      }
+    } else {
+      expression = new MethodInvocation(receiver, methodName, arguments, method)
+        ..fileOffset = fileOffset;
+    }
     Expression replacement;
     if (contravariantCheck) {
       // TODO(johnniwinther): Merge with the replacement computation below.
-      replacement = new AsExpression(
-          new MethodInvocation(receiver, methodName, arguments, method)
-            ..fileOffset = fileOffset,
-          result.inferredType)
+      replacement = new AsExpression(expression, result.inferredType)
         ..isTypeError = true
         ..isCovarianceCheck = true
         ..isForNonNullableByDefault = isNonNullableByDefault
@@ -2749,15 +2876,13 @@
         instrumentation.record(uriForInstrumentation, offset, 'checkReturn',
             new InstrumentationValueForType(result.inferredType));
       }
+    } else {
+      replacement = expression;
     }
 
     _checkBoundsInMethodInvocation(
         target, receiverType, calleeType, methodName, arguments, fileOffset);
 
-    replacement ??=
-        new MethodInvocation(receiver, methodName, arguments, method)
-          ..fileOffset = fileOffset;
-
     replacement = result.applyResult(replacement);
     if (!isTopLevel && target.isNullable) {
       if (isImplicitCall) {
@@ -2792,7 +2917,9 @@
       List<VariableDeclaration> hoistedExpressions,
       {bool isExpressionInvocation}) {
     assert(isExpressionInvocation != null);
-    assert(target.isInstanceMember || target.isNullableInstanceMember);
+    assert(target.isInstanceMember ||
+        target.isObjectMember ||
+        target.isNullableInstanceMember);
     Procedure getter = target.member;
     assert(getter.kind == ProcedureKind.Getter);
 
@@ -2828,8 +2955,33 @@
       receiver = _hoist(receiver, receiverType, hoistedExpressions);
     }
 
-    PropertyGet originalPropertyGet =
-        new PropertyGet(receiver, getter.name, getter)..fileOffset = fileOffset;
+    Name originalName = getter.name;
+    Expression originalReceiver = receiver;
+    Member originalTarget = getter;
+    Expression originalPropertyGet;
+    if (useNewMethodInvocationEncoding) {
+      InstanceAccessKind kind;
+      switch (target.kind) {
+        case ObjectAccessTargetKind.instanceMember:
+          kind = InstanceAccessKind.Instance;
+          break;
+        case ObjectAccessTargetKind.nullableInstanceMember:
+          kind = InstanceAccessKind.Nullable;
+          break;
+        case ObjectAccessTargetKind.objectMember:
+          kind = InstanceAccessKind.Object;
+          break;
+        default:
+          throw new UnsupportedError('Unexpected target kind $target');
+      }
+      originalPropertyGet = new InstanceGet(
+          kind, originalReceiver, originalName,
+          resultType: calleeType, interfaceTarget: originalTarget)
+        ..fileOffset = fileOffset;
+    } else {
+      originalPropertyGet = new PropertyGet(receiver, getter.name, getter)
+        ..fileOffset = fileOffset;
+    }
     Expression propertyGet = originalPropertyGet;
     if (calleeType is! DynamicType &&
         receiver is! ThisExpression &&
@@ -2886,11 +3038,29 @@
           nullAwareAction.receiver == originalPropertyGet) {
         invocationResult = new ExpressionInferenceResult(
             invocationResult.inferredType,
-            new MethodInvocation(
-                originalPropertyGet.receiver,
-                originalPropertyGet.name,
-                nullAwareAction.arguments,
-                originalPropertyGet.interfaceTarget)
+            new MethodInvocation(originalReceiver, originalName,
+                nullAwareAction.arguments, originalTarget)
+              ..fileOffset = nullAwareAction.fileOffset);
+      } else if (nullAwareAction is InstanceInvocation &&
+          nullAwareAction.receiver == originalPropertyGet) {
+        invocationResult = new ExpressionInferenceResult(
+            invocationResult.inferredType,
+            new MethodInvocation(originalReceiver, originalName,
+                nullAwareAction.arguments, originalTarget)
+              ..fileOffset = nullAwareAction.fileOffset);
+      } else if (nullAwareAction is DynamicInvocation &&
+          nullAwareAction.receiver == originalPropertyGet) {
+        invocationResult = new ExpressionInferenceResult(
+            invocationResult.inferredType,
+            new MethodInvocation(originalReceiver, originalName,
+                nullAwareAction.arguments, originalTarget)
+              ..fileOffset = nullAwareAction.fileOffset);
+      } else if (nullAwareAction is FunctionInvocation &&
+          nullAwareAction.receiver == originalPropertyGet) {
+        invocationResult = new ExpressionInferenceResult(
+            invocationResult.inferredType,
+            new MethodInvocation(originalReceiver, originalName,
+                nullAwareAction.arguments, originalTarget)
               ..fileOffset = nullAwareAction.fileOffset);
       }
     }
@@ -2937,7 +3107,9 @@
       List<VariableDeclaration> hoistedExpressions,
       {bool isExpressionInvocation}) {
     assert(isExpressionInvocation != null);
-    assert(target.isInstanceMember || target.isNullableInstanceMember);
+    assert(target.isInstanceMember ||
+        target.isObjectMember ||
+        target.isNullableInstanceMember);
     Field field = target.member;
 
     DartType calleeType = getGetterType(target, receiverType);
@@ -2952,8 +3124,34 @@
       receiver = _hoist(receiver, receiverType, hoistedExpressions);
     }
 
-    PropertyGet originalPropertyGet =
-        new PropertyGet(receiver, field.name, field)..fileOffset = fileOffset;
+    Name originalName = field.name;
+    Expression originalReceiver = receiver;
+    Member originalTarget = field;
+    Expression originalPropertyGet;
+    if (useNewMethodInvocationEncoding) {
+      InstanceAccessKind kind;
+      switch (target.kind) {
+        case ObjectAccessTargetKind.instanceMember:
+          kind = InstanceAccessKind.Instance;
+          break;
+        case ObjectAccessTargetKind.nullableInstanceMember:
+          kind = InstanceAccessKind.Nullable;
+          break;
+        case ObjectAccessTargetKind.objectMember:
+          kind = InstanceAccessKind.Object;
+          break;
+        default:
+          throw new UnsupportedError('Unexpected target kind $target');
+      }
+      originalPropertyGet = new InstanceGet(
+          kind, originalReceiver, originalName,
+          resultType: calleeType, interfaceTarget: originalTarget)
+        ..fileOffset = fileOffset;
+    } else {
+      originalPropertyGet =
+          new PropertyGet(originalReceiver, originalName, originalTarget)
+            ..fileOffset = fileOffset;
+    }
     Expression propertyGet = originalPropertyGet;
     if (receiver is! ThisExpression &&
         calleeType is! DynamicType &&
@@ -3011,11 +3209,29 @@
           nullAwareAction.receiver == originalPropertyGet) {
         invocationResult = new ExpressionInferenceResult(
             invocationResult.inferredType,
-            new MethodInvocation(
-                originalPropertyGet.receiver,
-                originalPropertyGet.name,
-                nullAwareAction.arguments,
-                originalPropertyGet.interfaceTarget)
+            new MethodInvocation(originalReceiver, originalName,
+                nullAwareAction.arguments, originalTarget)
+              ..fileOffset = nullAwareAction.fileOffset);
+      } else if (nullAwareAction is InstanceInvocation &&
+          nullAwareAction.receiver == originalPropertyGet) {
+        invocationResult = new ExpressionInferenceResult(
+            invocationResult.inferredType,
+            new MethodInvocation(originalReceiver, originalName,
+                nullAwareAction.arguments, originalTarget)
+              ..fileOffset = nullAwareAction.fileOffset);
+      } else if (nullAwareAction is DynamicInvocation &&
+          nullAwareAction.receiver == originalPropertyGet) {
+        invocationResult = new ExpressionInferenceResult(
+            invocationResult.inferredType,
+            new MethodInvocation(originalReceiver, originalName,
+                nullAwareAction.arguments, originalTarget)
+              ..fileOffset = nullAwareAction.fileOffset);
+      } else if (nullAwareAction is FunctionInvocation &&
+          nullAwareAction.receiver == originalPropertyGet) {
+        invocationResult = new ExpressionInferenceResult(
+            invocationResult.inferredType,
+            new MethodInvocation(originalReceiver, originalName,
+                nullAwareAction.arguments, originalTarget)
               ..fileOffset = nullAwareAction.fileOffset);
       }
     }
@@ -3049,6 +3265,7 @@
 
     switch (target.kind) {
       case ObjectAccessTargetKind.instanceMember:
+      case ObjectAccessTargetKind.objectMember:
       case ObjectAccessTargetKind.nullableInstanceMember:
         Member member = target.member;
         if (member is Procedure) {
@@ -3169,7 +3386,9 @@
         actualMethodName = callName;
       } else {
         actualReceiverType = receiverType;
-        interfaceTarget = target.isInstanceMember ? target.member : null;
+        interfaceTarget = (target.isInstanceMember || target.isObjectMember)
+            ? target.member
+            : null;
         actualMethodName = methodName;
       }
       library.checkBoundsInMethodInvocation(
@@ -3187,7 +3406,9 @@
 
   bool isSpecialCasedBinaryOperatorForReceiverType(
       ObjectAccessTarget target, DartType receiverType) {
-    return (target.isInstanceMember || target.isNullableInstanceMember) &&
+    return (target.isInstanceMember ||
+            target.isObjectMember ||
+            target.isNullableInstanceMember) &&
         target.member is Procedure &&
         typeSchemaEnvironment.isSpecialCasesBinaryForReceiverType(
             target.member, receiverType,
@@ -3195,7 +3416,9 @@
   }
 
   bool isSpecialCasedTernaryOperator(ObjectAccessTarget target) {
-    return (target.isInstanceMember || target.isNullableInstanceMember) &&
+    return (target.isInstanceMember ||
+            target.isObjectMember ||
+            target.isNullableInstanceMember) &&
         target.member is Procedure &&
         typeSchemaEnvironment.isSpecialCasedTernaryOperator(target.member,
             isNonNullableByDefault: isNonNullableByDefault);
@@ -3206,7 +3429,8 @@
       SuperMethodInvocation expression,
       DartType typeContext,
       ObjectAccessTarget target) {
-    assert(target.isInstanceMember || target.isMissing);
+    assert(
+        target.isInstanceMember || target.isObjectMember || target.isMissing);
     int fileOffset = expression.fileOffset;
     Name methodName = expression.name;
     Arguments arguments = expression.arguments;
@@ -3261,10 +3485,12 @@
   /// Performs the core type inference algorithm for super property get.
   ExpressionInferenceResult inferSuperPropertyGet(SuperPropertyGet expression,
       DartType typeContext, ObjectAccessTarget readTarget) {
-    assert(readTarget.isInstanceMember || readTarget.isMissing);
+    assert(readTarget.isInstanceMember ||
+        readTarget.isObjectMember ||
+        readTarget.isMissing);
     DartType receiverType = thisType;
     DartType inferredType = getGetterType(readTarget, receiverType);
-    if (readTarget.isInstanceMember) {
+    if (readTarget.isInstanceMember || readTarget.isObjectMember) {
       Member member = readTarget.member;
       if (member is Procedure && member.kind == ProcedureKind.Method) {
         return instantiateTearOff(inferredType, typeContext, expression);
@@ -3349,7 +3575,7 @@
       DartType receiverType, ObjectAccessTarget target,
       {bool isThisReceiver}) {
     assert(isThisReceiver != null);
-    if (target.isInstanceMember) {
+    if (target.isInstanceMember || target.isObjectMember) {
       Member interfaceMember = target.member;
       if (interfaceMember is Field ||
           interfaceMember is Procedure &&
@@ -3499,6 +3725,14 @@
       }
       return null;
     }
+    if (expression is StaticTearOff) {
+      Member target = expression.target;
+      if (target.enclosingClass != null) {
+        return templateInvalidCastStaticMethod;
+      } else {
+        return templateInvalidCastTopLevelFunction;
+      }
+    }
     if (expression is VariableGet) {
       VariableDeclaration variable = expression.variable;
       if (variable is VariableDeclarationImpl && variable.isLocalFunction) {
@@ -3723,6 +3957,25 @@
           templateAmbiguousExtensionOperator);
     }
   }
+
+  /// Creates a `e == null` test for the expression [left] using the
+  /// [fileOffset] as file offset for the created nodes and [equalsMember] as
+  /// the interface target of the created method invocation.
+  Expression createEqualsNull(
+      int fileOffset, Expression left, Member equalsMember) {
+    if (useNewMethodInvocationEncoding) {
+      return new EqualsNull(left, isNot: false)..fileOffset = fileOffset;
+    } else {
+      return new MethodInvocation(
+          left,
+          equalsName,
+          new Arguments(
+              <Expression>[new NullLiteral()..fileOffset = fileOffset])
+            ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset
+        ..interfaceTarget = equalsMember;
+    }
+  }
 }
 
 abstract class MixinInferrer {
@@ -3939,27 +4192,42 @@
 abstract class InvocationInferenceResult {
   DartType get inferredType;
 
+  DartType get functionType;
+
   /// Applies the result of the inference to the expression being inferred.
   ///
   /// A successful result leaves [expression] intact, and an error detected
   /// during inference would wrap the expression into an [InvalidExpression].
   Expression applyResult(Expression expression);
+
+  /// Returns `true` if the arguments of the call where not applicable to the
+  /// target.
+  bool get isInapplicable;
 }
 
 class SuccessfulInferenceResult implements InvocationInferenceResult {
   @override
   final DartType inferredType;
 
-  SuccessfulInferenceResult(this.inferredType);
+  @override
+  final FunctionType functionType;
+
+  SuccessfulInferenceResult(this.inferredType, this.functionType);
 
   @override
   Expression applyResult(Expression expression) => expression;
+
+  @override
+  bool get isInapplicable => false;
 }
 
 class WrapInProblemInferenceResult implements InvocationInferenceResult {
   @override
   final DartType inferredType;
 
+  @override
+  final DartType functionType;
+
   final Message message;
 
   final int fileOffset;
@@ -3968,8 +4236,13 @@
 
   final InferenceHelper helper;
 
-  WrapInProblemInferenceResult(this.inferredType, this.message, this.fileOffset,
-      this.length, this.helper);
+  @override
+  final bool isInapplicable;
+
+  WrapInProblemInferenceResult(this.inferredType, this.functionType,
+      this.message, this.fileOffset, this.length, this.helper,
+      {this.isInapplicable})
+      : assert(isInapplicable != null);
 
   @override
   Expression applyResult(Expression expression) {
@@ -4050,7 +4323,7 @@
     _inferrer.flowAnalysis.nullAwareAccess_end();
     // End non-nullable promotion of the initializer of [_nullAwareVariable].
     _inferrer.flowAnalysis.nullAwareAccess_end();
-    MethodInvocation equalsNull = createEqualsNull(_nullAwareFileOffset,
+    Expression equalsNull = _inferrer.createEqualsNull(_nullAwareFileOffset,
         createVariableGet(_nullAwareVariable), _nullAwareEquals);
     ConditionalExpression condition = new ConditionalExpression(
         equalsNull,
@@ -4109,14 +4382,18 @@
 }
 
 enum ObjectAccessTargetKind {
-  /// A valid access to a statically known instance member. The access is
-  /// either non-nullable or potentially nullable on a `Object` member.
+  /// A valid access to a statically known instance member on a non-nullable
+  /// receiver.
   instanceMember,
 
   /// A potentially nullable access to a statically known instance member. This
   /// is an erroneous case and a compile-time error is reported.
   nullableInstanceMember,
 
+  /// A valid access to a statically known instance Object member on a
+  /// potentially nullable receiver.
+  objectMember,
+
   /// A (non-nullable) access to the `.call` method of a function. This is used
   /// for access on `Function` and on function types.
   callFunction,
@@ -4172,6 +4449,13 @@
         member);
   }
 
+  /// Creates an access to the Object [member].
+  factory ObjectAccessTarget.objectMember(Member member) {
+    assert(member != null);
+    return new ObjectAccessTarget.internal(
+        ObjectAccessTargetKind.objectMember, member);
+  }
+
   /// Creates an access to the extension [member].
   factory ObjectAccessTarget.extensionMember(
       Member member,
@@ -4213,6 +4497,9 @@
   /// Returns `true` if this is an access to an instance member.
   bool get isInstanceMember => kind == ObjectAccessTargetKind.instanceMember;
 
+  /// Returns `true` if this is an access to an Object member.
+  bool get isObjectMember => kind == ObjectAccessTargetKind.objectMember;
+
   /// Returns `true` if this is an access to an extension member.
   bool get isExtensionMember => kind == ObjectAccessTargetKind.extensionMember;
 
diff --git a/pkg/front_end/lib/src/testing/id_extractor.dart b/pkg/front_end/lib/src/testing/id_extractor.dart
index f9fcbd3..5216459 100644
--- a/pkg/front_end/lib/src/testing/id_extractor.dart
+++ b/pkg/front_end/lib/src/testing/id_extractor.dart
@@ -196,6 +196,20 @@
     computeForMember(node);
   }
 
+  _visitInvocation(Expression node, Name name) {
+    if (name.name == '[]') {
+      computeForNode(node, computeDefaultNodeId(node));
+    } else if (name.name == '[]=') {
+      computeForNode(node, createUpdateId(node));
+    } else {
+      if (node.fileOffset != TreeNode.noOffset) {
+        // TODO(johnniwinther): Ensure file offset on all method invocations.
+        // Skip synthetic invocation created in the collection transformer.
+        computeForNode(node, createInvokeId(node));
+      }
+    }
+  }
+
   @override
   visitMethodInvocation(MethodInvocation node) {
     TreeNode receiver = node.receiver;
@@ -204,27 +218,58 @@
       // This is an invocation of a named local function.
       computeForNode(node, createInvokeId(node.receiver));
       node.arguments.accept(this);
-    } else if (node.name.text == '==' &&
+    } else if (node.name.name == '==' &&
         receiver is VariableGet &&
         receiver.variable.name == null) {
       // This is a desugared `?.`.
-    } else if (node.name.text == '[]') {
-      computeForNode(node, computeDefaultNodeId(node));
-      super.visitMethodInvocation(node);
-    } else if (node.name.text == '[]=') {
-      computeForNode(node, createUpdateId(node));
-      super.visitMethodInvocation(node);
     } else {
-      if (node.fileOffset != TreeNode.noOffset) {
-        // TODO(johnniwinther): Ensure file offset on all method invocations.
-        // Skip synthetic invocation created in the collection transformer.
-        computeForNode(node, createInvokeId(node));
-      }
+      _visitInvocation(node, node.name);
       super.visitMethodInvocation(node);
     }
   }
 
   @override
+  visitDynamicInvocation(DynamicInvocation node) {
+    _visitInvocation(node, node.name);
+    super.visitDynamicInvocation(node);
+  }
+
+  @override
+  visitFunctionInvocation(FunctionInvocation node) {
+    _visitInvocation(node, node.name);
+    super.visitFunctionInvocation(node);
+  }
+
+  @override
+  visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+    computeForNode(node, createInvokeId(node));
+    super.visitLocalFunctionInvocation(node);
+  }
+
+  @override
+  visitEqualsCall(EqualsCall node) {
+    _visitInvocation(node, Name.equalsName);
+    super.visitEqualsCall(node);
+  }
+
+  @override
+  visitEqualsNull(EqualsNull node) {
+    Expression receiver = node.expression;
+    if (receiver is VariableGet && receiver.variable.name == null) {
+      // This is a desugared `?.`.
+    } else {
+      _visitInvocation(node, Name.equalsName);
+    }
+    super.visitEqualsNull(node);
+  }
+
+  @override
+  visitInstanceInvocation(InstanceInvocation node) {
+    _visitInvocation(node, node.name);
+    super.visitInstanceInvocation(node);
+  }
+
+  @override
   visitLoadLibrary(LoadLibrary node) {
     computeForNode(node, createInvokeId(node));
   }
@@ -236,6 +281,30 @@
   }
 
   @override
+  visitDynamicGet(DynamicGet node) {
+    computeForNode(node, computeDefaultNodeId(node));
+    super.visitDynamicGet(node);
+  }
+
+  @override
+  visitFunctionTearOff(FunctionTearOff node) {
+    computeForNode(node, computeDefaultNodeId(node));
+    super.visitFunctionTearOff(node);
+  }
+
+  @override
+  visitInstanceGet(InstanceGet node) {
+    computeForNode(node, computeDefaultNodeId(node));
+    super.visitInstanceGet(node);
+  }
+
+  @override
+  visitInstanceTearOff(InstanceTearOff node) {
+    computeForNode(node, computeDefaultNodeId(node));
+    super.visitInstanceTearOff(node);
+  }
+
+  @override
   visitVariableDeclaration(VariableDeclaration node) {
     if (node.name != null && node.parent is! FunctionDeclaration) {
       // Skip synthetic variables and function declaration variables.
@@ -278,6 +347,18 @@
   }
 
   @override
+  visitDynamicSet(DynamicSet node) {
+    computeForNode(node, createUpdateId(node));
+    super.visitDynamicSet(node);
+  }
+
+  @override
+  visitInstanceSet(InstanceSet node) {
+    computeForNode(node, createUpdateId(node));
+    super.visitInstanceSet(node);
+  }
+
+  @override
   visitVariableSet(VariableSet node) {
     if (node.variable.name != null) {
       // Skip use of synthetic variables.
@@ -446,8 +527,11 @@
     TreeNode parent = node.parent;
     if (node.fileOffset == TreeNode.noOffset ||
         (parent is PropertyGet ||
+                parent is InstanceGet ||
                 parent is PropertySet ||
-                parent is MethodInvocation) &&
+                parent is InstanceSet ||
+                parent is MethodInvocation ||
+                parent is InstanceInvocation) &&
             parent.fileOffset == node.fileOffset) {
       // Skip implicit this expressions.
     } else {
@@ -479,6 +563,12 @@
   }
 
   @override
+  visitStaticTearOff(StaticTearOff node) {
+    computeForNode(node, computeDefaultNodeId(node));
+    super.visitStaticTearOff(node);
+  }
+
+  @override
   visitStaticSet(StaticSet node) {
     computeForNode(node, createUpdateId(node));
     super.visitStaticSet(node);
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 2350d4d..55c1399 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -315,6 +315,7 @@
 FastaUsageShort/analyzerCode: Fail
 FastaUsageShort/example: Fail
 FfiDartTypeMismatch/analyzerCode: Fail
+FfiEmptyStruct/analyzerCode: Fail
 FfiExceptionalReturnNull/analyzerCode: Fail
 FfiExpectedConstant/analyzerCode: Fail
 FfiExpectedExceptionalReturn/analyzerCode: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 5ca5154..e33cdcb 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -1914,7 +1914,7 @@
 
 IncrementalCompilerIllegalParameter:
   template: "Illegal parameter name '#string' found during expression compilation."
-  
+
 IncrementalCompilerIllegalTypeParameter:
   template: "Illegal type parameter name '#string' found during expression compilation."
 
@@ -4233,6 +4233,11 @@
   template: "Expected type '#type' to be '#type2', which is the Dart type corresponding to '#type3'."
   external: test/ffi_test.dart
 
+FfiEmptyStruct:
+  # Used by dart:ffi
+  template: "Struct '#name' is empty. Empty structs are undefined behavior."
+  external: test/ffi_test.dart
+
 FfiTypeInvalid:
   # Used by dart:ffi
   template: "Expected type '#type' to be a valid and instantiated subtype of 'NativeType'."
diff --git a/pkg/front_end/test/hot_reload_e2e_test.dart b/pkg/front_end/test/hot_reload_e2e_test.dart
index d64dcd3..eb41174 100644
--- a/pkg/front_end/test/hot_reload_e2e_test.dart
+++ b/pkg/front_end/test/hot_reload_e2e_test.dart
@@ -37,6 +37,8 @@
 
 import 'package:front_end/src/fasta/hybrid_file_system.dart'
     show HybridFileSystem;
+import 'package:kernel/target/targets.dart';
+import 'package:vm/target/vm.dart';
 
 import 'tool/reload.dart' show RemoteVm;
 
@@ -304,7 +306,9 @@
   var options = new CompilerOptions()
     ..sdkRoot = sdkRoot
     ..librariesSpecificationUri = Uri.base.resolve("sdk/lib/libraries.json")
-    ..fileSystem = fs;
+    ..fileSystem = fs
+    ..target = new VmTarget(new TargetFlags())
+    ..environmentDefines = {};
   return new IncrementalKernelGenerator(options, entryUri);
 }
 
diff --git a/pkg/front_end/test/messages_json_test.dart b/pkg/front_end/test/messages_json_test.dart
index e0f5620..55c6e76 100644
--- a/pkg/front_end/test/messages_json_test.dart
+++ b/pkg/front_end/test/messages_json_test.dart
@@ -20,8 +20,8 @@
 main() {
   for (int i = 0; i < Severity.values.length; i++) {
     Severity severity = Severity.values[i];
-    Code code = new Code("MyCodeName", null);
-    Message message = new Message(code);
+    Code code = new Code("MyCodeName");
+    Message message = new Message(code, message: '');
     LocatedMessage locatedMessage1 =
         new LocatedMessage(Uri.parse("what:ever/fun_1.dart"), 117, 2, message);
     FormattedMessage formattedMessage2 = new FormattedMessage(
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 6c4e50f..9b992fb 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -534,6 +534,7 @@
 indexing
 indirection
 individual
+inequality
 informative
 infos
 init
@@ -742,6 +743,7 @@
 nullary
 nullification
 nullify
+nullness
 nulls
 o
 oauth
@@ -902,6 +904,7 @@
 recalculation
 recall
 received
+receivers
 recheck
 recognizing
 recompiled
diff --git a/pkg/front_end/test/static_types/analysis_helper.dart b/pkg/front_end/test/static_types/analysis_helper.dart
index f6c6981..805194f 100644
--- a/pkg/front_end/test/static_types/analysis_helper.dart
+++ b/pkg/front_end/test/static_types/analysis_helper.dart
@@ -263,6 +263,24 @@
   }
 
   @override
+  void visitDynamicGet(DynamicGet node) {
+    registerError(node, "Dynamic access of '${node.name}'.");
+    super.visitDynamicGet(node);
+  }
+
+  @override
+  void visitDynamicSet(DynamicSet node) {
+    registerError(node, "Dynamic update to '${node.name}'.");
+    super.visitDynamicSet(node);
+  }
+
+  @override
+  void visitDynamicInvocation(DynamicInvocation node) {
+    registerError(node, "Dynamic invocation of '${node.name}'.");
+    super.visitDynamicInvocation(node);
+  }
+
+  @override
   void visitPropertyGet(PropertyGet node) {
     DartType receiverType = node.receiver.getStaticType(staticTypeContext);
     if (receiverType is DynamicType && node.interfaceTarget == null) {
diff --git a/pkg/front_end/test/static_types/cfe_allowed.json b/pkg/front_end/test/static_types/cfe_allowed.json
index 9dd0b5b..20c1a54 100644
--- a/pkg/front_end/test/static_types/cfe_allowed.json
+++ b/pkg/front_end/test/static_types/cfe_allowed.json
@@ -17,7 +17,6 @@
   "pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart": {
     "Dynamic access of 'data'.": 1,
     "Dynamic access of 'start'.": 1,
-    "Dynamic access of 'length'.": 1,
     "Dynamic access of 'boolValue'.": 2
   },
   "pkg/kernel/lib/transformations/value_class.dart": {
@@ -39,14 +38,5 @@
   },
   "pkg/front_end/lib/src/fasta/kernel/body_builder.dart": {
     "Dynamic invocation of 'buildForEffect'.": 1
-  },
-  "pkg/_fe_analyzer_shared/lib/src/util/link.dart": {
-    "Dynamic access of 'isEmpty'.": 1
-  },
-  "pkg/_fe_analyzer_shared/lib/src/util/link_implementation.dart": {
-    "Dynamic access of 'isNotEmpty'.": 1,
-    "Dynamic access of 'head'.": 1,
-    "Dynamic access of 'tail'.": 1,
-    "Dynamic access of 'isEmpty'.": 1
   }
 }
\ No newline at end of file
diff --git a/pkg/front_end/test/static_types/data/binary.dart b/pkg/front_end/test/static_types/data/binary.dart
new file mode 100644
index 0000000..6961e4f
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/binary.dart
@@ -0,0 +1,78 @@
+// 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.
+
+/*cfe.library: nnbd=false*/
+
+/*cfe:nnbd.library: nnbd=true*/
+
+num numTopLevel = /*cfe.int*/ /*cfe:nnbd.int!*/ 0;
+int intTopLevel = /*cfe.int*/ /*cfe:nnbd.int!*/ 0;
+double doubleTopLevel = /*cfe.double*/ /*cfe:nnbd.double!*/ 0.0;
+dynamic dynamicTopLevel = /*cfe.int*/ /*cfe:nnbd.int!*/ 0;
+
+main() {
+  /*cfe.num*/ /*cfe:nnbd.num!*/ numTopLevel
+      /*cfe.invoke: num*/ /*cfe:nnbd.invoke: num!*/ +
+      /*cfe.num*/ /*cfe:nnbd.num!*/ numTopLevel;
+
+  /*cfe.num*/ /*cfe:nnbd.num!*/ numTopLevel
+      /*cfe.invoke: num*/ /*cfe:nnbd.invoke: num!*/ +
+      /*cfe.int*/ /*cfe:nnbd.int!*/ intTopLevel;
+
+  /*cfe.num*/ /*cfe:nnbd.num!*/ numTopLevel
+      /*cfe.invoke: num*/ /*cfe:nnbd.invoke: double!*/ +
+      /*cfe.double*/ /*cfe:nnbd.double!*/ doubleTopLevel;
+
+  /*cfe.num*/ /*cfe:nnbd.num!*/ numTopLevel
+      /*cfe.invoke: num*/ /*cfe:nnbd.invoke: num!*/ +
+      /*as: num!*/ /*dynamic*/ dynamicTopLevel;
+
+  /*cfe.int*/ /*cfe:nnbd.int!*/ intTopLevel
+      /*cfe.invoke: num*/ /*cfe:nnbd.invoke: num!*/ +
+      /*cfe.num*/ /*cfe:nnbd.num!*/ numTopLevel;
+
+  /*cfe.int*/ /*cfe:nnbd.int!*/ intTopLevel
+      /*cfe.invoke: int*/ /*cfe:nnbd.invoke: int!*/ +
+      /*cfe.int*/ /*cfe:nnbd.int!*/ intTopLevel;
+
+  /*cfe.int*/ /*cfe:nnbd.int!*/ intTopLevel
+      /*cfe.invoke: double*/ /*cfe:nnbd.invoke: double!*/ +
+      /*cfe.double*/ /*cfe:nnbd.double!*/ doubleTopLevel;
+
+  /*cfe.int*/ /*cfe:nnbd.int!*/ intTopLevel
+      /*cfe.invoke: num*/ /*cfe:nnbd.invoke: num!*/ +
+      /*as: num!*/ /*dynamic*/ dynamicTopLevel;
+
+  /*cfe.double*/ /*cfe:nnbd.double!*/ doubleTopLevel
+      /*cfe.invoke: double*/ /*cfe:nnbd.invoke: double!*/ +
+      /*cfe.num*/ /*cfe:nnbd.num!*/ numTopLevel;
+
+  /*cfe.double*/ /*cfe:nnbd.double!*/ doubleTopLevel
+      /*cfe.invoke: double*/ /*cfe:nnbd.invoke: double!*/ +
+      /*cfe.int*/ /*cfe:nnbd.int!*/ intTopLevel;
+
+  /*cfe.double*/ /*cfe:nnbd.double!*/ doubleTopLevel
+      /*cfe.invoke: double*/ /*cfe:nnbd.invoke: double!*/ +
+      /*cfe.double*/ /*cfe:nnbd.double!*/ doubleTopLevel;
+
+  /*cfe.double*/ /*cfe:nnbd.double!*/ doubleTopLevel
+      /*cfe.invoke: double*/ /*cfe:nnbd.invoke: double!*/ +
+      /*as: num!*/ /*dynamic*/ dynamicTopLevel;
+
+  /*dynamic*/ dynamicTopLevel
+      /*invoke: dynamic*/ +
+      /*cfe.num*/ /*cfe:nnbd.num!*/ numTopLevel;
+
+  /*dynamic*/ dynamicTopLevel
+      /*invoke: dynamic*/ +
+      /*cfe.int*/ /*cfe:nnbd.int!*/ intTopLevel;
+
+  /*dynamic*/ dynamicTopLevel
+      /*invoke: dynamic*/ +
+      /*cfe.double*/ /*cfe:nnbd.double!*/ doubleTopLevel;
+
+  /*dynamic*/ dynamicTopLevel
+      /*invoke: dynamic*/ +
+      /*dynamic*/ dynamicTopLevel;
+}
diff --git a/pkg/front_end/test/static_types/data/never.dart b/pkg/front_end/test/static_types/data/never.dart
index b86d17f..b41471f 100644
--- a/pkg/front_end/test/static_types/data/never.dart
+++ b/pkg/front_end/test/static_types/data/never.dart
@@ -7,11 +7,11 @@
 // TODO(johnniwinther): Ensure static type of Never access is Never.
 
 propertyGet(Never never) {
-  var v1 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.dynamic*/ foo;
-  var v2 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.int!*/ hashCode;
-  var v3 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.Type!*/ runtimeType;
-  var v4 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.dynamic*/ toString;
-  var v5 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.dynamic*/ noSuchMethod;
+  var v1 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.Never*/ foo;
+  var v2 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.Never*/ hashCode;
+  var v3 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.Never*/ runtimeType;
+  var v4 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.Never*/ toString;
+  var v5 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.Never*/ noSuchMethod;
 }
 
 propertySet(Never never) {
@@ -20,28 +20,28 @@
 }
 
 methodInvocation(Never never, Invocation invocation) {
-  var v1 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.invoke: dynamic*/ foo();
-  var v2 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.invoke: dynamic*/ hashCode();
-  var v3 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.invoke: dynamic*/ runtimeType();
-  var v4 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.invoke: dynamic*/ toString();
+  var v1 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.invoke: Never*/ foo();
+  var v2 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.invoke: Never*/ hashCode();
+  var v3 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.invoke: Never*/ runtimeType();
+  var v4 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.invoke: Never*/ toString();
   var v5 = /*cfe:nnbd.Never*/ never
-      . /*cfe:nnbd.invoke: dynamic*/ toString(foo: /*cfe:nnbd.int!*/ 42);
-  var v6 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.invoke: dynamic*/ noSuchMethod(
+      . /*cfe:nnbd.invoke: Never*/ toString(foo: /*cfe:nnbd.int!*/ 42);
+  var v6 = /*cfe:nnbd.Never*/ never. /*cfe:nnbd.invoke: Never*/ noSuchMethod(
       /*cfe:nnbd.Invocation!*/ invocation);
   var v7 = /*cfe:nnbd.Never*/ never
-      . /*cfe:nnbd.invoke: dynamic*/ noSuchMethod(/*cfe:nnbd.int!*/ 42);
+      . /*cfe:nnbd.invoke: Never*/ noSuchMethod(/*cfe:nnbd.int!*/ 42);
 }
 
 equals(Never never) {
-  var v1 = /*cfe:nnbd.Never*/ never /*cfe:nnbd.invoke: bool!*/ == /*cfe:nnbd.Null*/ null;
-  var v2 = /*cfe:nnbd.Never*/ never /*cfe:nnbd.invoke: bool!*/ == /*cfe:nnbd.Never*/ never;
+  var v1 = /*cfe:nnbd.Never*/ never /*cfe:nnbd.invoke: bool!*/ == null;
+  var v2 = /*cfe:nnbd.Never*/ never /*cfe:nnbd.invoke: Never*/ == /*cfe:nnbd.Never*/ never;
 }
 
 operator(Never never) {
-  var v1 = /*cfe:nnbd.Never*/ never /*cfe:nnbd.invoke: dynamic*/ + /*cfe:nnbd.Never*/ never;
-  var v2 = /*cfe:nnbd.invoke: dynamic*/ - /*cfe:nnbd.Never*/ never;
-  var v3 = /*cfe:nnbd.Never*/ never /*cfe:nnbd.dynamic*/ [
+  var v1 = /*cfe:nnbd.Never*/ never /*cfe:nnbd.invoke: Never*/ + /*cfe:nnbd.Never*/ never;
+  var v2 = /*cfe:nnbd.invoke: Never*/ - /*cfe:nnbd.Never*/ never;
+  var v3 = /*cfe:nnbd.Never*/ never /*cfe:nnbd.Never*/ [
       /*cfe:nnbd.Never*/ never];
-  var v4 = /*cfe:nnbd.Never*/ never /*cfe:nnbd.update: dynamic*/ [
+  var v4 = /*cfe:nnbd.Never*/ never /*cfe:nnbd.update: Never*/ [
       /*cfe:nnbd.Never*/ never] = /*cfe:nnbd.Never*/ never;
 }
diff --git a/pkg/front_end/test/static_types/data/prefix_postfix.dart b/pkg/front_end/test/static_types/data/prefix_postfix.dart
index b40092f..c2a58d9 100644
--- a/pkg/front_end/test/static_types/data/prefix_postfix.dart
+++ b/pkg/front_end/test/static_types/data/prefix_postfix.dart
@@ -243,7 +243,8 @@
 testInstanceOnClass(Class c) {
   /*cfe.Class*/
   /*cfe:nnbd.Class!*/
-  c. /*cfe.update: num*/ /*cfe:nnbd.update: num!*/
+  c. /*cfe.update: num*/
+          /*cfe:nnbd.update: num!*/
           /*cfe.num*/
           /*cfe:nnbd.num!*/
           numInstance
@@ -255,7 +256,8 @@
 
   /*cfe.Class*/
   /*cfe:nnbd.Class!*/
-  c. /*cfe.update: num*/ /*cfe:nnbd.update: num!*/
+  c. /*cfe.update: num*/
+          /*cfe:nnbd.update: num!*/
           /*cfe.num*/
           /*cfe:nnbd.num!*/
           numInstance
diff --git a/pkg/front_end/test/text_representation/data/expressions.dart b/pkg/front_end/test/text_representation/data/expressions.dart
index cbad9e3..bf8c23c 100644
--- a/pkg/front_end/test/text_representation/data/expressions.dart
+++ b/pkg/front_end/test/text_representation/data/expressions.dart
@@ -421,12 +421,12 @@
       return t;
     };
 
-/*normal|limited.member: exprNullAware:let final Class? #0 = variable in #0.{Object.==}(null) ?{dynamic} null : #0{Class}.{Class.field}*/
-/*verbose.member: exprNullAware:let final expressions::Class? #0 = variable in #0.{dart.core::Object.==}(null) ?{dynamic} null : #0{expressions::Class}.{expressions::Class.field}*/
+/*normal|limited.member: exprNullAware:let final Class? #0 = variable in #0 == null ?{dynamic} null : #0{Class}.{Class.field}*/
+/*verbose.member: exprNullAware:let final expressions::Class? #0 = variable in #0 == null ?{dynamic} null : #0{expressions::Class}.{expressions::Class.field}*/
 exprNullAware(Class? variable) => variable?.field;
 
-/*normal|limited.member: exprIfNull:let final int? #0 = i in #0.{num.==}(null) ?{int} 42 : #0{int}*/
-/*verbose.member: exprIfNull:let final dart.core::int? #0 = i in #0.{dart.core::num.==}(null) ?{dart.core::int} 42 : #0{dart.core::int}*/
+/*normal|limited.member: exprIfNull:let final int? #0 = i in #0 == null ?{int} 42 : #0{int}*/
+/*verbose.member: exprIfNull:let final dart.core::int? #0 = i in #0 == null ?{dart.core::int} 42 : #0{dart.core::int}*/
 exprIfNull(int? i) => i ?? 42;
 
 /*normal|limited.member: exprNestedDeep:<Object>[1, <Object>[2, <Object>[3, <int>[4]]]]*/
@@ -483,3 +483,21 @@
 /*normal|limited.member: exprPrecedence4:(b ?{int} 0 : 1).{num.+}(2)*/
 /*verbose.member: exprPrecedence4:(b ?{dart.core::int} 0 : 1).{dart.core::num.+}(2)*/
 exprPrecedence4(bool b) => (b ? 0 : 1) + 2;
+
+/*member: exprAssignmentEqualsNull1:(a = b) == null*/
+exprAssignmentEqualsNull1(String a, String b) => (a = b) == null;
+
+/*member: exprAssignmentEqualsNull2:a = b == null*/
+exprAssignmentEqualsNull2(bool a, String b) => a = b == null;
+
+/*member: exprAssignmentEqualsNull3:a = b == null*/
+exprAssignmentEqualsNull3(bool a, String b) => a = (b == null);
+
+/*member: exprAssignmentEquals1:(a = b) == c*/
+exprAssignmentEquals1(String a, String b, String c) => (a = b) == c;
+
+/*member: exprAssignmentEquals2:a = b == c*/
+exprAssignmentEquals2(bool a, String b, String c) => a = b == c;
+
+/*member: exprAssignmentEquals3:a = b == c*/
+exprAssignmentEquals3(bool a, String b, String c) => a = (b == c);
diff --git a/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart b/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart
index 6c6582b..7279fce 100644
--- a/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart
+++ b/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart
@@ -616,7 +616,38 @@
 
 void _testIfNullExtensionIndexSet() {}
 
-void _testCompoundIndexSet() {}
+void _testCompoundIndexSet() {
+  testExpression(
+      new CompoundIndexSet(new IntLiteral(0), new IntLiteral(1), new Name('+'),
+          new IntLiteral(2),
+          forEffect: false, forPostIncDec: false),
+      '''
+0[1] += 2''');
+  testExpression(
+      new CompoundIndexSet(new IntLiteral(0), new IntLiteral(1), new Name('+'),
+          new IntLiteral(1),
+          forEffect: false, forPostIncDec: true),
+      '''
+0[1]++''');
+  testExpression(
+      new CompoundIndexSet(new IntLiteral(0), new IntLiteral(1), new Name('-'),
+          new IntLiteral(1),
+          forEffect: false, forPostIncDec: true),
+      '''
+0[1]--''');
+  testExpression(
+      new CompoundIndexSet(new IntLiteral(0), new IntLiteral(1), new Name('*'),
+          new IntLiteral(1),
+          forEffect: false, forPostIncDec: true),
+      '''
+0[1] *= 1''');
+  testExpression(
+      new CompoundIndexSet(new IntLiteral(0), new IntLiteral(1), new Name('+'),
+          new IntLiteral(2),
+          forEffect: false, forPostIncDec: true),
+      '''
+0[1] += 2''');
+}
 
 void _testNullAwareCompoundSet() {
   testExpression(
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/number_folds.dart.outline.expect b/pkg/front_end/testcases/general/constants/js_semantics/number_folds.dart.outline.expect
index 2f0bfb0..7a9b06e 100644
--- a/pkg/front_end/testcases/general/constants/js_semantics/number_folds.dart.outline.expect
+++ b/pkg/front_end/testcases/general/constants/js_semantics/number_folds.dart.outline.expect
@@ -29,32 +29,32 @@
 import self as self;
 import "dart:core" as core;
 
-static const field core::int* shiftNegative1 = 2.{core::int::<<}(1.{core::int::unary-}());
+static const field core::int* shiftNegative1 = 2.{core::int::<<}(1.{core::int::unary-}(){() →* core::int}){(core::int) →* core::int*};
 static const field core::int* shiftNegative2 = invalid-expression "pkg/front_end/testcases/general/constants/js_semantics/number_folds.dart:6:30: Error: The operator '>>>' isn't defined for the class 'int'.
 Try correcting the operator to an existing operator, or defining a '>>>' operator.
 const int shiftNegative2 = 2 >>> -1;
                              ^^^" as{TypeError,ForDynamic} core::int*;
-static const field core::int* shiftNegative3 = 2.{core::int::>>}(1.{core::int::unary-}());
-static const field core::int* modZero = 2.{core::num::%}(0);
+static const field core::int* shiftNegative3 = 2.{core::int::>>}(1.{core::int::unary-}(){() →* core::int}){(core::int) →* core::int*};
+static const field core::int* modZero = 2.{core::num::%}(0){(core::num) →* core::int*};
 static const field core::int* divZero = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/constants/js_semantics/number_folds.dart:9:23: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
 const int divZero = 2 / 0;
-                      ^" in 2.{core::num::/}(0) as{TypeError} core::int*;
-static const field core::int* intdivZero = 2.{core::num::~/}(0);
-static const field core::int* unaryMinus = 2.{core::int::unary-}();
-static const field core::int* unaryTilde = 2.{core::int::~}();
+                      ^" in 2.{core::num::/}(0){(core::num) →* core::double*} as{TypeError} core::int*;
+static const field core::int* intdivZero = 2.{core::num::~/}(0){(core::num) →* core::int*};
+static const field core::int* unaryMinus = 2.{core::int::unary-}(){() →* core::int};
+static const field core::int* unaryTilde = 2.{core::int::~}(){() →* core::int};
 static const field core::int* unaryPlus = invalid-expression "pkg/front_end/testcases/general/constants/js_semantics/number_folds.dart:13:23: Error: This couldn't be parsed.
 const int unaryPlus = +2;
-                      ^".+(2) as{TypeError,ForDynamic} core::int*;
-static const field core::int* binaryPlus = 40.{core::num::+}(2);
-static const field core::int* binaryMinus = 44.{core::num::-}(2);
-static const field core::int* binaryTimes = 21.{core::num::*}(2);
-static const field core::double* binaryDiv = 84.{core::num::/}(2);
-static const field core::int* binaryTildeDiv = 84.{core::num::~/}(2);
-static const field core::int* binaryMod = 85.{core::num::%}(43);
-static const field core::int* binaryOr = 32.{core::int::|}(10);
-static const field core::int* binaryAnd = 63.{core::int::&}(106);
-static const field core::int* binaryXor = 63.{core::int::^}(21);
-static const field core::int* binaryShift1 = 21.{core::int::<<}(1);
+                      ^"{dynamic}.+(2) as{TypeError,ForDynamic} core::int*;
+static const field core::int* binaryPlus = 40.{core::num::+}(2){(core::num) →* core::int*};
+static const field core::int* binaryMinus = 44.{core::num::-}(2){(core::num) →* core::int*};
+static const field core::int* binaryTimes = 21.{core::num::*}(2){(core::num) →* core::int*};
+static const field core::double* binaryDiv = 84.{core::num::/}(2){(core::num) →* core::double*};
+static const field core::int* binaryTildeDiv = 84.{core::num::~/}(2){(core::num) →* core::int*};
+static const field core::int* binaryMod = 85.{core::num::%}(43){(core::num) →* core::int*};
+static const field core::int* binaryOr = 32.{core::int::|}(10){(core::int) →* core::int*};
+static const field core::int* binaryAnd = 63.{core::int::&}(106){(core::int) →* core::int*};
+static const field core::int* binaryXor = 63.{core::int::^}(21){(core::int) →* core::int*};
+static const field core::int* binaryShift1 = 21.{core::int::<<}(1){(core::int) →* core::int*};
 static const field core::int* binaryShift2 = invalid-expression "pkg/front_end/testcases/general/constants/js_semantics/number_folds.dart:27:29: Error: The operator '>>>' isn't defined for the class 'int'.
 Try correcting the operator to an existing operator, or defining a '>>>' operator.
 const int binaryShift2 = 84 >>> 1;
@@ -63,45 +63,45 @@
 Try correcting the operator to an existing operator, or defining a '>>>' operator.
 const int binaryShift3 = 21 >>> 64;
                             ^^^" as{TypeError,ForDynamic} core::int*;
-static const field core::int* binaryShift4 = 84.{core::int::>>}(1);
-static const field core::int* binaryShift5 = 1.{core::int::unary-}().{core::int::>>}(1);
-static const field core::bool* binaryLess = 42.{core::num::<}(42);
-static const field core::bool* binaryLessEqual = 42.{core::num::<=}(42);
-static const field core::bool* binaryGreaterEqual = 42.{core::num::>=}(42);
-static const field core::bool* binaryGreater = 42.{core::num::>}(42);
-static const field core::int* doubleTruncateDiv = 84.2.{core::double::~/}(2);
-static const field core::int* doubleTruncateDivZero = 84.2.{core::double::~/}(0);
-static const field core::int* doubleTruncateDivNull = 84.2.{core::double::~/}(null);
-static const field core::double* doubleNan = 0.{core::num::/}(0);
-static const field core::int* doubleTruncateDivNaN = 84.2.{core::double::~/}(self::doubleNan);
+static const field core::int* binaryShift4 = 84.{core::int::>>}(1){(core::int) →* core::int*};
+static const field core::int* binaryShift5 = 1.{core::int::unary-}(){() →* core::int}.{core::int::>>}(1){(core::int) →* core::int*};
+static const field core::bool* binaryLess = 42.{core::num::<}(42){(core::num) →* core::bool*};
+static const field core::bool* binaryLessEqual = 42.{core::num::<=}(42){(core::num) →* core::bool*};
+static const field core::bool* binaryGreaterEqual = 42.{core::num::>=}(42){(core::num) →* core::bool*};
+static const field core::bool* binaryGreater = 42.{core::num::>}(42){(core::num) →* core::bool*};
+static const field core::int* doubleTruncateDiv = 84.2.{core::double::~/}(2){(core::num) →* core::int*};
+static const field core::int* doubleTruncateDivZero = 84.2.{core::double::~/}(0){(core::num) →* core::int*};
+static const field core::int* doubleTruncateDivNull = 84.2.{core::double::~/}(null){(core::num) →* core::int*};
+static const field core::double* doubleNan = 0.{core::num::/}(0){(core::num) →* core::double*};
+static const field core::int* doubleTruncateDivNaN = 84.2.{core::double::~/}(self::doubleNan){(core::num) →* core::int*};
 static const field core::int* bigNumber = -9223372036854775808;
 static method main() → dynamic
   ;
 
 
 Extra constant evaluation status:
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:5:33 -> DoubleConstant(-1.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:7:33 -> DoubleConstant(-1.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:9:23 -> DoubleConstant(Infinity)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:11:24 -> DoubleConstant(-2.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:12:24 -> DoubleConstant(4294967293.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:15:27 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:16:28 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:17:28 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:18:29 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:19:30 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:20:26 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:21:25 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:22:26 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:23:26 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:24:29 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:30:29 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:31:29 -> DoubleConstant(4294967295.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:32:28 -> BoolConstant(false)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:33:33 -> BoolConstant(true)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:34:36 -> BoolConstant(true)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:35:31 -> BoolConstant(false)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:37:36 -> DoubleConstant(42.0)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///number_folds.dart:40:27 -> DoubleConstant(NaN)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:5:33 -> DoubleConstant(-1.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:7:33 -> DoubleConstant(-1.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:9:23 -> DoubleConstant(Infinity)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:11:24 -> DoubleConstant(-2.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:12:24 -> DoubleConstant(4294967293.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:15:27 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:16:28 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:17:28 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:18:29 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:19:30 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:20:26 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:21:25 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:22:26 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:23:26 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:24:29 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:30:29 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:31:29 -> DoubleConstant(4294967295.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:32:28 -> BoolConstant(false)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:33:33 -> BoolConstant(true)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:34:36 -> BoolConstant(true)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:35:31 -> BoolConstant(false)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:37:36 -> DoubleConstant(42.0)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///number_folds.dart:40:27 -> DoubleConstant(NaN)
 Evaluated: StaticGet @ org-dartlang-testcase:///number_folds.dart:41:42 -> DoubleConstant(NaN)
 Extra constant evaluation: evaluated: 38, effectively constant: 24
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/various.dart.outline.expect b/pkg/front_end/testcases/general/constants/js_semantics/various.dart.outline.expect
index 41ed046..9bf843f 100644
--- a/pkg/front_end/testcases/general/constants/js_semantics/various.dart.outline.expect
+++ b/pkg/front_end/testcases/general/constants/js_semantics/various.dart.outline.expect
@@ -25,17 +25,17 @@
 static const field core::bool* zeroPointZeroIdentical = core::identical(0.0, 0.0);
 static const field core::bool* zeroPointZeroIdenticalToZero = core::identical(0.0, 0);
 static const field core::bool* zeroIdenticalToZeroPointZero = core::identical(0, 0.0);
-static const field core::bool* nanIdentical = core::identical(0.{core::num::/}(0), 0.{core::num::/}(0));
+static const field core::bool* nanIdentical = core::identical(0.{core::num::/}(0){(core::num) →* core::double*}, 0.{core::num::/}(0){(core::num) →* core::double*});
 static const field core::bool* stringIdentical = core::identical("hello", "hello");
 static const field core::bool* string2Identical = core::identical("hello", "world");
-static const field core::bool* zeroPointZeroEqual = 0.0.{core::num::==}(0.0);
-static const field core::bool* zeroPointZeroEqualToZero = 0.0.{core::num::==}(0);
-static const field core::bool* zeroEqualToZeroPointZero = 0.{core::num::==}(0.0);
-static const field core::bool* nanEqual = 0.{core::num::/}(0).{core::num::==}(0.{core::num::/}(0));
-static const field core::bool* stringEqual = "hello".{core::String::==}("hello");
-static const field core::bool* string2Equal = "hello".{core::String::==}("world");
+static const field core::bool* zeroPointZeroEqual = 0.0 =={core::num::==}{(core::Object) → core::bool} 0.0;
+static const field core::bool* zeroPointZeroEqualToZero = 0.0 =={core::num::==}{(core::Object) → core::bool} 0;
+static const field core::bool* zeroEqualToZeroPointZero = 0 =={core::num::==}{(core::Object) → core::bool} 0.0;
+static const field core::bool* nanEqual = 0.{core::num::/}(0){(core::num) →* core::double*} =={core::num::==}{(core::Object) → core::bool} 0.{core::num::/}(0){(core::num) →* core::double*};
+static const field core::bool* stringEqual = "hello" =={core::String::==}{(core::Object) → core::bool} "hello";
+static const field core::bool* string2Equal = "hello" =={core::String::==}{(core::Object) → core::bool} "world";
 static const field core::int* intFortyTwo = 42;
-static const field core::String* intStringConcat = "hello${self::intFortyTwo.{core::num::*}(self::intFortyTwo)}";
+static const field core::String* intStringConcat = "hello${self::intFortyTwo.{core::num::*}(self::intFortyTwo){(core::num) →* core::int*}}";
 
 
 Extra constant evaluation status:
@@ -61,11 +61,11 @@
 Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:35:22 -> BoolConstant(false)
 Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:36:25 -> BoolConstant(true)
 Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:37:26 -> BoolConstant(false)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///various.dart:39:32 -> BoolConstant(true)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///various.dart:40:38 -> BoolConstant(true)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///various.dart:41:36 -> BoolConstant(true)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///various.dart:42:24 -> BoolConstant(false)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///various.dart:43:29 -> BoolConstant(true)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///various.dart:44:30 -> BoolConstant(false)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:39:32 -> BoolConstant(true)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:40:38 -> BoolConstant(true)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:41:36 -> BoolConstant(true)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:42:24 -> BoolConstant(false)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:43:29 -> BoolConstant(true)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:44:30 -> BoolConstant(false)
 Evaluated: StringConcatenation @ org-dartlang-testcase:///various.dart:47:30 -> StringConstant("hello1764")
 Extra constant evaluation: evaluated: 29, effectively constant: 29
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.outline.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.outline.expect
index 9745070..0d9ff2d 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.outline.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.outline.expect
@@ -12,13 +12,13 @@
 class Foo extends core::Object /*hasConstConstructor*/  {
   final field core::int x;
   const constructor •(core::int x) → self::Foo
-    : self::Foo::x = x, assert(x.{core::num::>}(0), "x is not positive"), assert(x.{core::num::>}(0)), assert(const core::bool::fromEnvironment("foo").{core::Object::==}(false), "foo was ${const core::bool::fromEnvironment("foo")}"), assert(const core::bool::fromEnvironment("foo").{core::Object::==}(false)), super core::Object::•()
+    : self::Foo::x = x, assert(x.{core::num::>}(0){(core::num) → core::bool}, "x is not positive"), assert(x.{core::num::>}(0){(core::num) → core::bool}), assert(const core::bool::fromEnvironment("foo") =={core::Object::==}{(core::Object) → core::bool} false, "foo was ${const core::bool::fromEnvironment("foo")}"), assert(const core::bool::fromEnvironment("foo") =={core::Object::==}{(core::Object) → core::bool} false), super core::Object::•()
     ;
   const constructor withMessage(core::int x) → self::Foo
-    : self::Foo::x = x, assert(x.{core::num::<}(0), "btw foo was ${const core::bool::fromEnvironment("foo")}"), super core::Object::•()
+    : self::Foo::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}, "btw foo was ${const core::bool::fromEnvironment("foo")}"), super core::Object::•()
     ;
   const constructor withInvalidMessage(core::int x) → self::Foo
-    : self::Foo::x = x, assert(x.{core::num::<}(0), x), super core::Object::•()
+    : self::Foo::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}, x), super core::Object::•()
     ;
   const constructor withInvalidCondition(core::int x) → self::Foo
     : self::Foo::x = x, assert(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart:16:51: Error: A value of type 'int' can't be assigned to a variable of type 'bool'.
@@ -29,10 +29,10 @@
 class Bar extends core::Object /*hasConstConstructor*/  {
   final field core::int x;
   const constructor withMessage(core::int x) → self::Bar
-    : self::Bar::x = x, assert(x.{core::num::<}(0), "x is not negative"), super core::Object::•()
+    : self::Bar::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}, "x is not negative"), super core::Object::•()
     ;
   const constructor withoutMessage(core::int x) → self::Bar
-    : self::Bar::x = x, assert(x.{core::num::<}(0)), super core::Object::•()
+    : self::Bar::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}), super core::Object::•()
     ;
 }
 static const field self::Foo foo1 = const self::Foo::•(1);
@@ -49,11 +49,11 @@
 
 
 Extra constant evaluation status:
-Evaluated with empty environment: MethodInvocation @ org-dartlang-testcase:///const_asserts.dart:10:50 -> BoolConstant(true)
+Evaluated with empty environment: EqualsCall @ org-dartlang-testcase:///const_asserts.dart:10:50 -> BoolConstant(true)
 Evaluated with empty environment: FactoryConstructorInvocationJudgment @ org-dartlang-testcase:///const_asserts.dart:10:22 -> BoolConstant(false)
 Evaluated with empty environment: StringConcatenation @ org-dartlang-testcase:///const_asserts.dart:11:59 -> StringConstant("foo was false")
 Evaluated with empty environment: FactoryConstructorInvocationJudgment @ org-dartlang-testcase:///const_asserts.dart:11:30 -> BoolConstant(false)
-Evaluated with empty environment: MethodInvocation @ org-dartlang-testcase:///const_asserts.dart:12:50 -> BoolConstant(true)
+Evaluated with empty environment: EqualsCall @ org-dartlang-testcase:///const_asserts.dart:12:50 -> BoolConstant(true)
 Evaluated with empty environment: FactoryConstructorInvocationJudgment @ org-dartlang-testcase:///const_asserts.dart:12:22 -> BoolConstant(false)
 Evaluated with empty environment: StringConcatenation @ org-dartlang-testcase:///const_asserts.dart:14:73 -> StringConstant("btw foo was false")
 Evaluated with empty environment: FactoryConstructorInvocationJudgment @ org-dartlang-testcase:///const_asserts.dart:14:44 -> BoolConstant(false)
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.strong.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.strong.expect
index 786c05f..07c4e9d 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.strong.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.strong.expect
@@ -72,13 +72,13 @@
 class Foo extends core::Object /*hasConstConstructor*/  {
   final field core::int x;
   const constructor •(core::int x) → self::Foo
-    : self::Foo::x = x, assert(x.{core::num::>}(0), "x is not positive"), assert(x.{core::num::>}(0)), assert((#C2).{core::Object::==}(false), "foo was ${#C3}"), assert((#C4).{core::Object::==}(false)), super core::Object::•()
+    : self::Foo::x = x, assert(x.{core::num::>}(0){(core::num) → core::bool}, "x is not positive"), assert(x.{core::num::>}(0){(core::num) → core::bool}), assert((#C2) =={core::Object::==}{(core::Object) → core::bool} false, "foo was ${#C3}"), assert((#C4) =={core::Object::==}{(core::Object) → core::bool} false), super core::Object::•()
     ;
   const constructor withMessage(core::int x) → self::Foo
-    : self::Foo::x = x, assert(x.{core::num::<}(0), "btw foo was ${#C5}"), super core::Object::•()
+    : self::Foo::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}, "btw foo was ${#C5}"), super core::Object::•()
     ;
   const constructor withInvalidMessage(core::int x) → self::Foo
-    : self::Foo::x = x, assert(x.{core::num::<}(0), x), super core::Object::•()
+    : self::Foo::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}, x), super core::Object::•()
     ;
   const constructor withInvalidCondition(core::int x) → self::Foo
     : self::Foo::x = x, assert(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart:16:51: Error: A value of type 'int' can't be assigned to a variable of type 'bool'.
@@ -89,10 +89,10 @@
 class Bar extends core::Object /*hasConstConstructor*/  {
   final field core::int x;
   const constructor withMessage(core::int x) → self::Bar
-    : self::Bar::x = x, assert(x.{core::num::<}(0), "x is not negative"), super core::Object::•()
+    : self::Bar::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}, "x is not negative"), super core::Object::•()
     ;
   const constructor withoutMessage(core::int x) → self::Bar
-    : self::Bar::x = x, assert(x.{core::num::<}(0)), super core::Object::•()
+    : self::Bar::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}), super core::Object::•()
     ;
 }
 static const field self::Foo foo1 = #C9;
@@ -119,7 +119,7 @@
   #C6 = 1
   #C7 = false
   #C8 = "foo was "
-  #C9 = eval self::Foo{x:#C6, assert(const core::bool::fromEnvironment(#C1).==(#C7), "${#C8}${const core::bool::fromEnvironment(#C1)}"), assert(const core::bool::fromEnvironment(#C1).==(#C7))}
+  #C9 = eval self::Foo{x:#C6, assert(const core::bool::fromEnvironment(#C1) =={core::Object::==}{(core::Object) → core::bool} (#C7), "${#C8}${const core::bool::fromEnvironment(#C1)}"), assert(const core::bool::fromEnvironment(#C1) =={core::Object::==}{(core::Object) → core::bool} (#C7))}
   #C10 = 42
   #C11 = "btw foo was "
   #C12 = eval self::Foo{x:#C10, assert(#C7, "${#C11}${const core::bool::fromEnvironment(#C1)}")}
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.strong.transformed.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.strong.transformed.expect
index b31130f..5db03b0 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart.strong.transformed.expect
@@ -72,13 +72,13 @@
 class Foo extends core::Object /*hasConstConstructor*/  {
   final field core::int x;
   const constructor •(core::int x) → self::Foo
-    : self::Foo::x = x, assert(x.{core::num::>}(0), "x is not positive"), assert(x.{core::num::>}(0)), assert((#C2).{core::Object::==}(false), "foo was ${#C3}"), assert((#C4).{core::Object::==}(false)), super core::Object::•()
+    : self::Foo::x = x, assert(x.{core::num::>}(0){(core::num) → core::bool}, "x is not positive"), assert(x.{core::num::>}(0){(core::num) → core::bool}), assert((#C2) =={core::Object::==}{(core::Object) → core::bool} false, "foo was ${#C3}"), assert((#C4) =={core::Object::==}{(core::Object) → core::bool} false), super core::Object::•()
     ;
   const constructor withMessage(core::int x) → self::Foo
-    : self::Foo::x = x, assert(x.{core::num::<}(0), "btw foo was ${#C5}"), super core::Object::•()
+    : self::Foo::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}, "btw foo was ${#C5}"), super core::Object::•()
     ;
   const constructor withInvalidMessage(core::int x) → self::Foo
-    : self::Foo::x = x, assert(x.{core::num::<}(0), x), super core::Object::•()
+    : self::Foo::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}, x), super core::Object::•()
     ;
   const constructor withInvalidCondition(core::int x) → self::Foo
     : self::Foo::x = x, assert(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/const_asserts.dart:16:51: Error: A value of type 'int' can't be assigned to a variable of type 'bool'.
@@ -89,10 +89,10 @@
 class Bar extends core::Object /*hasConstConstructor*/  {
   final field core::int x;
   const constructor withMessage(core::int x) → self::Bar
-    : self::Bar::x = x, assert(x.{core::num::<}(0), "x is not negative"), super core::Object::•()
+    : self::Bar::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}, "x is not negative"), super core::Object::•()
     ;
   const constructor withoutMessage(core::int x) → self::Bar
-    : self::Bar::x = x, assert(x.{core::num::<}(0)), super core::Object::•()
+    : self::Bar::x = x, assert(x.{core::num::<}(0){(core::num) → core::bool}), super core::Object::•()
     ;
 }
 static const field self::Foo foo1 = #C9;
@@ -119,19 +119,19 @@
   #C6 = 1
   #C7 = false
   #C8 = "foo was "
-  #C9 = eval self::Foo{x:#C6, assert(const core::bool::fromEnvironment(#C1).==(#C7), "${#C8}${const core::bool::fromEnvironment(#C1)}"), assert(const core::bool::fromEnvironment(#C1).==(#C7))}
+  #C9 = eval self::Foo{x:#C6, assert(const core::bool::fromEnvironment(#C1) =={core::Object::==}{(core::Object) → core::bool} (#C7), "${#C8}${const core::bool::fromEnvironment(#C1)}"), assert(const core::bool::fromEnvironment(#C1) =={core::Object::==}{(core::Object) → core::bool} (#C7))}
   #C10 = 42
   #C11 = "btw foo was "
   #C12 = eval self::Foo{x:#C10, assert(#C7, "${#C11}${const core::bool::fromEnvironment(#C1)}")}
-  #C13 = eval self::Foo{x:#C6, assert(const core::bool::fromEnvironment(#C1).==(#C7), "${#C8}${const core::bool::fromEnvironment(#C1)}"), assert(const core::bool::fromEnvironment(#C1).==(#C7))}
+  #C13 = eval self::Foo{x:#C6, assert(const core::bool::fromEnvironment(#C1) =={core::Object::==}{(core::Object) → core::bool} (#C7), "${#C8}${const core::bool::fromEnvironment(#C1)}"), assert(const core::bool::fromEnvironment(#C1) =={core::Object::==}{(core::Object) → core::bool} (#C7))}
 }
 
 Extra constant evaluation status:
-Evaluated with empty environment: MethodInvocation @ org-dartlang-testcase:///const_asserts.dart:10:50 -> BoolConstant(true)
+Evaluated with empty environment: EqualsCall @ org-dartlang-testcase:///const_asserts.dart:10:50 -> BoolConstant(true)
 Evaluated with empty environment: ConstantExpression @ org-dartlang-testcase:///const_asserts.dart:10:22 -> BoolConstant(false)
 Evaluated with empty environment: StringConcatenation @ org-dartlang-testcase:///const_asserts.dart:11:59 -> StringConstant("foo was false")
 Evaluated with empty environment: ConstantExpression @ org-dartlang-testcase:///const_asserts.dart:11:30 -> BoolConstant(false)
-Evaluated with empty environment: MethodInvocation @ org-dartlang-testcase:///const_asserts.dart:12:50 -> BoolConstant(true)
+Evaluated with empty environment: EqualsCall @ org-dartlang-testcase:///const_asserts.dart:12:50 -> BoolConstant(true)
 Evaluated with empty environment: ConstantExpression @ org-dartlang-testcase:///const_asserts.dart:12:22 -> BoolConstant(false)
 Evaluated with empty environment: StringConcatenation @ org-dartlang-testcase:///const_asserts.dart:14:73 -> StringConstant("btw foo was false")
 Evaluated with empty environment: ConstantExpression @ org-dartlang-testcase:///const_asserts.dart:14:44 -> BoolConstant(false)
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/rudimentary_test_01.dart.outline.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/rudimentary_test_01.dart.outline.expect
index 55d4864..a4388e8 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/rudimentary_test_01.dart.outline.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/rudimentary_test_01.dart.outline.expect
@@ -2,9 +2,9 @@
 import self as self;
 import "dart:core" as core;
 
-static const field core::int foo = 42.{core::num::*}(42);
+static const field core::int foo = 42.{core::num::*}(42){(core::num) → core::int};
 static const field core::String bar = "hello ${const core::String::fromEnvironment("baz", defaultValue: "world")}!";
-static const field core::bool baz = true && true && (false || true) && 42.{core::num::==}(21.{core::num::*}(4).{core::num::/}(2));
+static const field core::bool baz = true && true && (false || true) && 42 =={core::num::==}{(core::Object) → core::bool} 21.{core::num::*}(4){(core::num) → core::int}.{core::num::/}(2){(core::num) → core::double};
 static const field core::Symbol blaSymbol = #_x;
 static method main() → dynamic
   ;
@@ -13,7 +13,7 @@
 
 
 Extra constant evaluation status:
-Evaluated: MethodInvocation @ org-dartlang-testcase:///rudimentary_test_01.dart:5:20 -> IntConstant(1764)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///rudimentary_test_01.dart:5:20 -> IntConstant(1764)
 Evaluated with empty environment: StringConcatenation @ org-dartlang-testcase:///rudimentary_test_01.dart:6:18 -> StringConstant("hello world!")
 Evaluated with empty environment: FactoryConstructorInvocationJudgment @ org-dartlang-testcase:///rudimentary_test_01.dart:7:27 -> StringConstant("world")
 Evaluated: LogicalExpression @ org-dartlang-testcase:///rudimentary_test_01.dart:8:50 -> BoolConstant(true)
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.outline.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.outline.expect
index e60e513..9d8a83e 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.outline.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.outline.expect
@@ -76,7 +76,7 @@
     : this self::Class::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart:100:34: Error: The argument type 'A' can't be assigned to the parameter type 'T'.
  - 'A' is from 'pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart'.
   const Class.method(T t) : this(-t);
-                                 ^" in t.{self::A::unary-}() as{TypeError,ForNonNullableByDefault} <BottomType>)
+                                 ^" in t.{self::A::unary-}(){() → self::A} as{TypeError,ForNonNullableByDefault} <BottomType>)
     ;
 }
 class Subclass<T extends self::A = self::A> extends self::Class<self::Subclass::T> /*hasConstConstructor*/  {
@@ -96,7 +96,7 @@
 static const field core::bool barFromEnvOrNull = const core::bool::fromEnvironment("bar", defaultValue: self::barFromEnvOrNull0!);
 static const field core::bool notBarFromEnvOrNull = !self::barFromEnvOrNull;
 static const field core::bool conditionalOnNull = self::barFromEnvOrNull ?{core::bool} true : false;
-static const field core::bool nullAwareOnNull = let final core::bool #t2 = self::barFromEnvOrNull in #t2.{core::Object::==}(null) ?{core::bool} true : #t2;
+static const field core::bool nullAwareOnNull = let final core::bool #t2 = self::barFromEnvOrNull in #t2 == null ?{core::bool} true : #t2;
 static const field core::bool andOnNull = self::barFromEnvOrNull && true;
 static const field core::bool andOnNull2 = true && self::barFromEnvOrNull;
 static const field core::bool orOnNull = self::barFromEnvOrNull || true;
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.strong.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.strong.expect
index 141047c..3c0c3ba 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.strong.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.strong.expect
@@ -104,7 +104,7 @@
     : this self::Class::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart:100:34: Error: The argument type 'A' can't be assigned to the parameter type 'T'.
  - 'A' is from 'pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart'.
   const Class.method(T t) : this(-t);
-                                 ^" in t.{self::A::unary-}() as{TypeError,ForNonNullableByDefault} <BottomType>)
+                                 ^" in t.{self::A::unary-}(){() → self::A} as{TypeError,ForNonNullableByDefault} <BottomType>)
     ;
 }
 class Subclass<T extends self::A = self::A> extends self::Class<self::Subclass::T> /*hasConstConstructor*/  {
@@ -191,8 +191,8 @@
   core::print(#C37);
   core::print(#C38);
   core::print(#C20);
-  core::print((#C20).{self::Foo::saved});
-  core::print((#C20).{self::Foo::value});
+  core::print((#C20).{self::Foo::saved}{core::bool});
+  core::print((#C20).{self::Foo::value}{core::int});
 }
 
 library /*isNonNullableByDefault*/;
@@ -216,7 +216,7 @@
   #C12 = eval !const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!)
   #C13 = false
   #C14 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!) ?{core::bool} #C8 : #C13
-  #C15 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!).==(#C9) ?{core::bool} #C8 : const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!)
+  #C15 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!) == null ?{core::bool} #C8 : const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!)
   #C16 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!) && (#C8)
   #C17 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!) || (#C8)
   #C18 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!) || (#C13)
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.strong.transformed.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.strong.transformed.expect
index 0a49faa..b0c66e2 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart.strong.transformed.expect
@@ -104,7 +104,7 @@
     : this self::Class::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart:100:34: Error: The argument type 'A' can't be assigned to the parameter type 'T'.
  - 'A' is from 'pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various.dart'.
   const Class.method(T t) : this(-t);
-                                 ^" in t.{self::A::unary-}() as{TypeError,ForNonNullableByDefault} <BottomType>)
+                                 ^" in t.{self::A::unary-}(){() → self::A} as{TypeError,ForNonNullableByDefault} <BottomType>)
     ;
 }
 class Subclass<T extends self::A = self::A> extends self::Class<self::Subclass::T> /*hasConstConstructor*/  {
@@ -191,8 +191,8 @@
   core::print(#C50);
   core::print(#C51);
   core::print(#C52);
-  core::print((#C52).{self::Foo::saved});
-  core::print((#C52).{self::Foo::value});
+  core::print((#C52).{self::Foo::saved}{core::bool});
+  core::print((#C52).{self::Foo::value}{core::int});
 }
 
 library /*isNonNullableByDefault*/;
@@ -216,7 +216,7 @@
   #C12 = eval !const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!)
   #C13 = false
   #C14 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!) ?{core::bool} #C8 : #C13
-  #C15 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!).==(#C9) ?{core::bool} #C8 : const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!)
+  #C15 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!) == null ?{core::bool} #C8 : const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!)
   #C16 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!) && (#C8)
   #C17 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!) || (#C8)
   #C18 = eval const core::bool::fromEnvironment(#C2, defaultValue: (const core::bool::fromEnvironment(#C2) ?{core::bool?} #C8 : #C9)!) || (#C13)
diff --git a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various_2.dart.outline.expect b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various_2.dart.outline.expect
index 4b3859b..1578765 100644
--- a/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various_2.dart.outline.expect
+++ b/pkg/front_end/testcases/general/constants/with_unevaluated_agnostic/various_2.dart.outline.expect
@@ -110,13 +110,13 @@
 Evaluated: StaticInvocation @ org-dartlang-testcase:///various_2.dart:53:5 -> BoolConstant(true)
 Evaluated: StaticInvocation @ org-dartlang-testcase:///various_2.dart:55:5 -> BoolConstant(true)
 Evaluated: TypeLiteral @ org-dartlang-testcase:///various_2_lib.dart:17:27 -> TypeLiteralConstant(Object)
-Evaluated: StaticGet @ org-dartlang-testcase:///various_2_lib.dart:18:12 -> TearOffConstant(identical)
+Evaluated: StaticTearOff @ org-dartlang-testcase:///various_2_lib.dart:18:12 -> TearOffConstant(identical)
 Evaluated with empty environment: ConditionalExpression @ org-dartlang-testcase:///various_2_lib.dart:20:39 -> PartialInstantiationConstant(id2<int>)
 Evaluated with empty environment: FactoryConstructorInvocationJudgment @ org-dartlang-testcase:///various_2_lib.dart:20:11 -> BoolConstant(false)
 Evaluated with empty environment: Instantiation @ org-dartlang-testcase:///various_2_lib.dart:20:41 -> PartialInstantiationConstant(id1<int>)
-Evaluated: StaticGet @ org-dartlang-testcase:///various_2_lib.dart:20:41 -> TearOffConstant(id1)
+Evaluated: StaticTearOff @ org-dartlang-testcase:///various_2_lib.dart:20:41 -> TearOffConstant(id1)
 Evaluated with empty environment: Instantiation @ org-dartlang-testcase:///various_2_lib.dart:20:47 -> PartialInstantiationConstant(id2<int>)
-Evaluated: StaticGet @ org-dartlang-testcase:///various_2_lib.dart:20:47 -> TearOffConstant(id2)
+Evaluated: StaticTearOff @ org-dartlang-testcase:///various_2_lib.dart:20:47 -> TearOffConstant(id2)
 Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various_2_lib.dart:21:24 -> InstanceConstant(const Class<int>{Class.field: 0})
 Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various_2_lib.dart:22:25 -> InstanceConstant(const Class<dynamic>{Class.field: const <int>[42]})
 Evaluated: TypeLiteral @ org-dartlang-testcase:///various_2_lib.dart:23:29 -> TypeLiteralConstant(dynamic Function(dynamic))
diff --git a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.strong.expect b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.strong.expect
index 4321535..54ba4eb 100644
--- a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.strong.expect
+++ b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.strong.expect
@@ -112,21 +112,21 @@
 }
 static field core::bool* enableRead = true;
 static method read(core::int* value) → core::int*
-  return self::enableRead ?{core::int*} value : 1.{core::int::unary-}();
+  return self::enableRead ?{core::int*} value : 1.{core::int::unary-}(){() →* core::int};
 static method method1() → core::int*
   return 0;
 static method method2(core::int* a) → core::int*
-  return a.{core::int::unary-}();
+  return a.{core::int::unary-}(){() →* core::int};
 static method method3(core::int* a, core::int* b) → core::int*
-  return a.{core::num::-}(b);
+  return a.{core::num::-}(b){(core::num) →* core::int*};
 static method method4(core::int* a, [core::int* b = #C8]) → core::int*
-  return a.{core::num::-}(b);
+  return a.{core::num::-}(b){(core::num) →* core::int*};
 static method method5([core::int* a = #C8, core::int* b = #C8]) → core::int*
-  return a.{core::num::-}(b);
+  return a.{core::num::-}(b){(core::num) →* core::int*};
 static method method6(core::int* a, {core::int* b = #C8}) → core::int*
-  return a.{core::num::-}(b);
+  return a.{core::num::-}(b){(core::num) →* core::int*};
 static method method7({core::int* a = #C8, core::int* b = #C8}) → core::int*
-  return a.{core::num::-}(b);
+  return a.{core::num::-}(b){(core::num) →* core::int*};
 static method main() → dynamic {
   self::callField(new self::Class::•());
   self::callGetter(new self::Class::•());
@@ -136,42 +136,42 @@
 static method callField(self::Class* c) → dynamic {
   self::expect(0, c.{self::Class::field1a}());
   self::expect(0, c.{self::Class::field1b}());
-  self::expect(42.{core::int::unary-}(), let final self::Class* #t1 = c in let final core::int* #t2 = self::read(42) in #t1.{self::Class::field2}(#t2));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t3 = c in let final core::int* #t4 = self::read(12) in let final core::int* #t5 = self::read(23) in #t3.{self::Class::field3}(#t4, #t5));
+  self::expect(42.{core::int::unary-}(){() →* core::int}, let final self::Class* #t1 = c in let final core::int* #t2 = self::read(42) in #t1.{self::Class::field2}(#t2));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t3 = c in let final core::int* #t4 = self::read(12) in let final core::int* #t5 = self::read(23) in #t3.{self::Class::field3}(#t4, #t5));
   self::expect(12, let final self::Class* #t6 = c in let final core::int* #t7 = self::read(12) in #t6.{self::Class::field4}(#t7));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t8 = c in let final core::int* #t9 = self::read(12) in let final core::int* #t10 = self::read(23) in #t8.{self::Class::field4}(#t9, #t10));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t8 = c in let final core::int* #t9 = self::read(12) in let final core::int* #t10 = self::read(23) in #t8.{self::Class::field4}(#t9, #t10));
   self::expect(0, c.{self::Class::field5}());
   self::expect(12, let final self::Class* #t11 = c in let final core::int* #t12 = self::read(12) in #t11.{self::Class::field5}(#t12));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t13 = c in let final core::int* #t14 = self::read(12) in let final core::int* #t15 = self::read(23) in #t13.{self::Class::field5}(#t14, #t15));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t13 = c in let final core::int* #t14 = self::read(12) in let final core::int* #t15 = self::read(23) in #t13.{self::Class::field5}(#t14, #t15));
   self::expect(12, let final self::Class* #t16 = c in let final core::int* #t17 = self::read(12) in #t16.{self::Class::field6}(#t17));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t18 = c in let final core::int* #t19 = self::read(12) in let final core::int* #t20 = self::read(23) in #t18.{self::Class::field6}(#t19, b: #t20));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t18 = c in let final core::int* #t19 = self::read(12) in let final core::int* #t20 = self::read(23) in #t18.{self::Class::field6}(#t19, b: #t20));
   self::expect(0, c.{self::Class::field7}());
   self::expect(12, let final self::Class* #t21 = c in let final core::int* #t22 = self::read(12) in #t21.{self::Class::field7}(a: #t22));
-  self::expect(23.{core::int::unary-}(), let final self::Class* #t23 = c in let final core::int* #t24 = self::read(23) in #t23.{self::Class::field7}(b: #t24));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t25 = c in let final core::int* #t26 = self::read(12) in let final core::int* #t27 = self::read(23) in #t25.{self::Class::field7}(a: #t26, b: #t27));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t28 = c in let final core::int* #t29 = self::read(23) in let final core::int* #t30 = self::read(12) in #t28.{self::Class::field7}(b: #t29, a: #t30));
+  self::expect(23.{core::int::unary-}(){() →* core::int}, let final self::Class* #t23 = c in let final core::int* #t24 = self::read(23) in #t23.{self::Class::field7}(b: #t24));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t25 = c in let final core::int* #t26 = self::read(12) in let final core::int* #t27 = self::read(23) in #t25.{self::Class::field7}(a: #t26, b: #t27));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t28 = c in let final core::int* #t29 = self::read(23) in let final core::int* #t30 = self::read(12) in #t28.{self::Class::field7}(b: #t29, a: #t30));
 }
 static method callGetter(self::Class* c) → dynamic {
   self::expect(0, c.{self::Class::getter1a}());
   self::expect(0, c.{self::Class::getter1b}());
-  self::expect(42.{core::int::unary-}(), let final self::Class* #t31 = c in let final core::int* #t32 = self::read(42) in #t31.{self::Class::getter2}(#t32));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t33 = c in let final core::int* #t34 = self::read(12) in let final core::int* #t35 = self::read(23) in #t33.{self::Class::getter3}(#t34, #t35));
+  self::expect(42.{core::int::unary-}(){() →* core::int}, let final self::Class* #t31 = c in let final core::int* #t32 = self::read(42) in #t31.{self::Class::getter2}(#t32));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t33 = c in let final core::int* #t34 = self::read(12) in let final core::int* #t35 = self::read(23) in #t33.{self::Class::getter3}(#t34, #t35));
   self::expect(12, let final self::Class* #t36 = c in let final core::int* #t37 = self::read(12) in #t36.{self::Class::getter4}(#t37));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t38 = c in let final core::int* #t39 = self::read(12) in let final core::int* #t40 = self::read(23) in #t38.{self::Class::getter4}(#t39, #t40));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t38 = c in let final core::int* #t39 = self::read(12) in let final core::int* #t40 = self::read(23) in #t38.{self::Class::getter4}(#t39, #t40));
   self::expect(0, c.{self::Class::getter5}());
   self::expect(12, let final self::Class* #t41 = c in let final core::int* #t42 = self::read(12) in #t41.{self::Class::getter5}(#t42));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t43 = c in let final core::int* #t44 = self::read(12) in let final core::int* #t45 = self::read(23) in #t43.{self::Class::getter5}(#t44, #t45));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t43 = c in let final core::int* #t44 = self::read(12) in let final core::int* #t45 = self::read(23) in #t43.{self::Class::getter5}(#t44, #t45));
   self::expect(12, let final self::Class* #t46 = c in let final core::int* #t47 = self::read(12) in #t46.{self::Class::getter6}(#t47));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t48 = c in let final core::int* #t49 = self::read(12) in let final core::int* #t50 = self::read(23) in #t48.{self::Class::getter6}(#t49, b: #t50));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t48 = c in let final core::int* #t49 = self::read(12) in let final core::int* #t50 = self::read(23) in #t48.{self::Class::getter6}(#t49, b: #t50));
   self::expect(0, c.{self::Class::getter7}());
   self::expect(12, let final self::Class* #t51 = c in let final core::int* #t52 = self::read(12) in #t51.{self::Class::getter7}(a: #t52));
-  self::expect(23.{core::int::unary-}(), let final self::Class* #t53 = c in let final core::int* #t54 = self::read(23) in #t53.{self::Class::getter7}(b: #t54));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t55 = c in let final core::int* #t56 = self::read(12) in let final core::int* #t57 = self::read(23) in #t55.{self::Class::getter7}(a: #t56, b: #t57));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t58 = c in let final core::int* #t59 = self::read(23) in let final core::int* #t60 = self::read(12) in #t58.{self::Class::getter7}(b: #t59, a: #t60));
+  self::expect(23.{core::int::unary-}(){() →* core::int}, let final self::Class* #t53 = c in let final core::int* #t54 = self::read(23) in #t53.{self::Class::getter7}(b: #t54));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t55 = c in let final core::int* #t56 = self::read(12) in let final core::int* #t57 = self::read(23) in #t55.{self::Class::getter7}(a: #t56, b: #t57));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t58 = c in let final core::int* #t59 = self::read(23) in let final core::int* #t60 = self::read(12) in #t58.{self::Class::getter7}(b: #t59, a: #t60));
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
   self::enableRead = true;
-  if(!expected.{core::Object::==}(actual))
+  if(expected !={core::Object::==}{(core::Object) → core::bool} actual)
     throw "Expected ${expected}, ${actual}";
 }
 
diff --git a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.strong.transformed.expect b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.strong.transformed.expect
index e9cba62..19610d1 100644
--- a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.strong.transformed.expect
@@ -112,21 +112,21 @@
 }
 static field core::bool* enableRead = true;
 static method read(core::int* value) → core::int*
-  return self::enableRead ?{core::int*} value : 1.{core::int::unary-}();
+  return self::enableRead ?{core::int*} value : 1.{core::int::unary-}(){() →* core::int};
 static method method1() → core::int*
   return 0;
 static method method2(core::int* a) → core::int*
-  return a.{core::int::unary-}();
+  return a.{core::int::unary-}(){() →* core::int};
 static method method3(core::int* a, core::int* b) → core::int*
-  return a.{core::num::-}(b);
+  return a.{core::num::-}(b){(core::num) →* core::int*};
 static method method4(core::int* a, [core::int* b = #C8]) → core::int*
-  return a.{core::num::-}(b);
+  return a.{core::num::-}(b){(core::num) →* core::int*};
 static method method5([core::int* a = #C8, core::int* b = #C8]) → core::int*
-  return a.{core::num::-}(b);
+  return a.{core::num::-}(b){(core::num) →* core::int*};
 static method method6(core::int* a, {core::int* b = #C8}) → core::int*
-  return a.{core::num::-}(b);
+  return a.{core::num::-}(b){(core::num) →* core::int*};
 static method method7({core::int* a = #C8, core::int* b = #C8}) → core::int*
-  return a.{core::num::-}(b);
+  return a.{core::num::-}(b){(core::num) →* core::int*};
 static method main() → dynamic {
   self::callField(new self::Class::•());
   self::callGetter(new self::Class::•());
@@ -136,42 +136,42 @@
 static method callField(self::Class* c) → dynamic {
   self::expect(0, c.{self::Class::field1a}());
   self::expect(0, c.{self::Class::field1b}());
-  self::expect(42.{core::int::unary-}(), let final self::Class* #t1 = c in let final core::int* #t2 = self::read(42) in #t1.{self::Class::field2}(#t2));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t3 = c in let final core::int* #t4 = self::read(12) in let final core::int* #t5 = self::read(23) in #t3.{self::Class::field3}(#t4, #t5));
+  self::expect(42.{core::int::unary-}(){() →* core::int}, let final self::Class* #t1 = c in let final core::int* #t2 = self::read(42) in #t1.{self::Class::field2}(#t2));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t3 = c in let final core::int* #t4 = self::read(12) in let final core::int* #t5 = self::read(23) in #t3.{self::Class::field3}(#t4, #t5));
   self::expect(12, let final self::Class* #t6 = c in let final core::int* #t7 = self::read(12) in #t6.{self::Class::field4}(#t7));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t8 = c in let final core::int* #t9 = self::read(12) in let final core::int* #t10 = self::read(23) in #t8.{self::Class::field4}(#t9, #t10));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t8 = c in let final core::int* #t9 = self::read(12) in let final core::int* #t10 = self::read(23) in #t8.{self::Class::field4}(#t9, #t10));
   self::expect(0, c.{self::Class::field5}());
   self::expect(12, let final self::Class* #t11 = c in let final core::int* #t12 = self::read(12) in #t11.{self::Class::field5}(#t12));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t13 = c in let final core::int* #t14 = self::read(12) in let final core::int* #t15 = self::read(23) in #t13.{self::Class::field5}(#t14, #t15));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t13 = c in let final core::int* #t14 = self::read(12) in let final core::int* #t15 = self::read(23) in #t13.{self::Class::field5}(#t14, #t15));
   self::expect(12, let final self::Class* #t16 = c in let final core::int* #t17 = self::read(12) in #t16.{self::Class::field6}(#t17));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t18 = c in let final core::int* #t19 = self::read(12) in let final core::int* #t20 = self::read(23) in #t18.{self::Class::field6}(#t19, b: #t20));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t18 = c in let final core::int* #t19 = self::read(12) in let final core::int* #t20 = self::read(23) in #t18.{self::Class::field6}(#t19, b: #t20));
   self::expect(0, c.{self::Class::field7}());
   self::expect(12, let final self::Class* #t21 = c in let final core::int* #t22 = self::read(12) in #t21.{self::Class::field7}(a: #t22));
-  self::expect(23.{core::int::unary-}(), let final self::Class* #t23 = c in let final core::int* #t24 = self::read(23) in #t23.{self::Class::field7}(b: #t24));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t25 = c in let final core::int* #t26 = self::read(12) in let final core::int* #t27 = self::read(23) in #t25.{self::Class::field7}(a: #t26, b: #t27));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t28 = c in let final core::int* #t29 = self::read(23) in let final core::int* #t30 = self::read(12) in #t28.{self::Class::field7}(b: #t29, a: #t30));
+  self::expect(23.{core::int::unary-}(){() →* core::int}, let final self::Class* #t23 = c in let final core::int* #t24 = self::read(23) in #t23.{self::Class::field7}(b: #t24));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t25 = c in let final core::int* #t26 = self::read(12) in let final core::int* #t27 = self::read(23) in #t25.{self::Class::field7}(a: #t26, b: #t27));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t28 = c in let final core::int* #t29 = self::read(23) in let final core::int* #t30 = self::read(12) in #t28.{self::Class::field7}(b: #t29, a: #t30));
 }
 static method callGetter(self::Class* c) → dynamic {
   self::expect(0, c.{self::Class::getter1a}());
   self::expect(0, c.{self::Class::getter1b}());
-  self::expect(42.{core::int::unary-}(), let final self::Class* #t31 = c in let final core::int* #t32 = self::read(42) in #t31.{self::Class::getter2}(#t32));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t33 = c in let final core::int* #t34 = self::read(12) in let final core::int* #t35 = self::read(23) in #t33.{self::Class::getter3}(#t34, #t35));
+  self::expect(42.{core::int::unary-}(){() →* core::int}, let final self::Class* #t31 = c in let final core::int* #t32 = self::read(42) in #t31.{self::Class::getter2}(#t32));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t33 = c in let final core::int* #t34 = self::read(12) in let final core::int* #t35 = self::read(23) in #t33.{self::Class::getter3}(#t34, #t35));
   self::expect(12, let final self::Class* #t36 = c in let final core::int* #t37 = self::read(12) in #t36.{self::Class::getter4}(#t37));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t38 = c in let final core::int* #t39 = self::read(12) in let final core::int* #t40 = self::read(23) in #t38.{self::Class::getter4}(#t39, #t40));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t38 = c in let final core::int* #t39 = self::read(12) in let final core::int* #t40 = self::read(23) in #t38.{self::Class::getter4}(#t39, #t40));
   self::expect(0, c.{self::Class::getter5}());
   self::expect(12, let final self::Class* #t41 = c in let final core::int* #t42 = self::read(12) in #t41.{self::Class::getter5}(#t42));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t43 = c in let final core::int* #t44 = self::read(12) in let final core::int* #t45 = self::read(23) in #t43.{self::Class::getter5}(#t44, #t45));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t43 = c in let final core::int* #t44 = self::read(12) in let final core::int* #t45 = self::read(23) in #t43.{self::Class::getter5}(#t44, #t45));
   self::expect(12, let final self::Class* #t46 = c in let final core::int* #t47 = self::read(12) in #t46.{self::Class::getter6}(#t47));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t48 = c in let final core::int* #t49 = self::read(12) in let final core::int* #t50 = self::read(23) in #t48.{self::Class::getter6}(#t49, b: #t50));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t48 = c in let final core::int* #t49 = self::read(12) in let final core::int* #t50 = self::read(23) in #t48.{self::Class::getter6}(#t49, b: #t50));
   self::expect(0, c.{self::Class::getter7}());
   self::expect(12, let final self::Class* #t51 = c in let final core::int* #t52 = self::read(12) in #t51.{self::Class::getter7}(a: #t52));
-  self::expect(23.{core::int::unary-}(), let final self::Class* #t53 = c in let final core::int* #t54 = self::read(23) in #t53.{self::Class::getter7}(b: #t54));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t55 = c in let final core::int* #t56 = self::read(12) in let final core::int* #t57 = self::read(23) in #t55.{self::Class::getter7}(a: #t56, b: #t57));
-  self::expect(11.{core::int::unary-}(), let final self::Class* #t58 = c in let final core::int* #t59 = self::read(23) in let final core::int* #t60 = self::read(12) in #t58.{self::Class::getter7}(b: #t59, a: #t60));
+  self::expect(23.{core::int::unary-}(){() →* core::int}, let final self::Class* #t53 = c in let final core::int* #t54 = self::read(23) in #t53.{self::Class::getter7}(b: #t54));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t55 = c in let final core::int* #t56 = self::read(12) in let final core::int* #t57 = self::read(23) in #t55.{self::Class::getter7}(a: #t56, b: #t57));
+  self::expect(11.{core::int::unary-}(){() →* core::int}, let final self::Class* #t58 = c in let final core::int* #t59 = self::read(23) in let final core::int* #t60 = self::read(12) in #t58.{self::Class::getter7}(b: #t59, a: #t60));
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
   self::enableRead = true;
-  if(!expected.{core::Object::==}(actual))
+  if(expected !={core::Object::==}{(core::Object) → core::bool} actual)
     throw "Expected ${expected}, ${actual}";
 }
 
@@ -187,21 +187,21 @@
 }
 
 Extra constant evaluation status:
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:7:45 -> IntConstant(-1)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:130:10 -> IntConstant(-42)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:131:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:133:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:136:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:138:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:141:10 -> IntConstant(-23)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:142:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:143:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:149:10 -> IntConstant(-42)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:150:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:152:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:155:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:157:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:160:10 -> IntConstant(-23)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:161:10 -> IntConstant(-11)
-Evaluated: MethodInvocation @ org-dartlang-testcase:///getter_call.dart:162:10 -> IntConstant(-11)
-Extra constant evaluation: evaluated: 322, effectively constant: 17
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:7:45 -> IntConstant(-1)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:130:10 -> IntConstant(-42)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:131:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:133:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:136:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:138:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:141:10 -> IntConstant(-23)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:142:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:143:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:149:10 -> IntConstant(-42)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:150:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:152:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:155:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:157:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:160:10 -> IntConstant(-23)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:161:10 -> IntConstant(-11)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///getter_call.dart:162:10 -> IntConstant(-11)
+Extra constant evaluation: evaluated: 321, effectively constant: 17
diff --git a/pkg/front_end/testcases/implicit_getter_calls/this_field_call.dart.strong.expect b/pkg/front_end/testcases/implicit_getter_calls/this_field_call.dart.strong.expect
index 3c9883b..21856f2 100644
--- a/pkg/front_end/testcases/implicit_getter_calls/this_field_call.dart.strong.expect
+++ b/pkg/front_end/testcases/implicit_getter_calls/this_field_call.dart.strong.expect
@@ -21,5 +21,5 @@
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
 static method main() → dynamic {
-  new self::A::•<core::int*>((core::int* x) → Null {}).{self::A::foo}(3);
+  new self::A::•<core::int*>((core::int* x) → Null {}).{self::A::foo}(3){(core::int*) →* dynamic};
 }
diff --git a/pkg/front_end/testcases/implicit_getter_calls/this_field_call.dart.strong.transformed.expect b/pkg/front_end/testcases/implicit_getter_calls/this_field_call.dart.strong.transformed.expect
index 3c9883b..21856f2 100644
--- a/pkg/front_end/testcases/implicit_getter_calls/this_field_call.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/implicit_getter_calls/this_field_call.dart.strong.transformed.expect
@@ -21,5 +21,5 @@
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
 static method main() → dynamic {
-  new self::A::•<core::int*>((core::int* x) → Null {}).{self::A::foo}(3);
+  new self::A::•<core::int*>((core::int* x) → Null {}).{self::A::foo}(3){(core::int*) →* dynamic};
 }
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.1.expect
index 7648024..c42f8e4 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.1.expect
@@ -64,5 +64,5 @@
       ;
   }
   static method method() → dynamic
-    return new mai::SubClass::•().{mai2::_Class&SuperClass&Mixin::method}(0);
+    return new mai::SubClass::•().{mai2::_Class&SuperClass&Mixin::method}(0){(dart.core::num*) →* void};
 }
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.2.expect
index 1fdd7b3..92a39af 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.2.expect
@@ -65,5 +65,5 @@
       ;
   }
   static method method() → dynamic
-    return new mai::SubClass::•().{mai2::_Class&SuperClass&Mixin::method}(0);
+    return new mai::SubClass::•().{mai2::_Class&SuperClass&Mixin::method}(0){(dart.core::num*) →* void};
 }
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.3.expect
index 7648024..c42f8e4 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.3.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/mixin_application_declares.yaml.world.3.expect
@@ -64,5 +64,5 @@
       ;
   }
   static method method() → dynamic
-    return new mai::SubClass::•().{mai2::_Class&SuperClass&Mixin::method}(0);
+    return new mai::SubClass::•().{mai2::_Class&SuperClass&Mixin::method}(0){(dart.core::num*) →* void};
 }
diff --git a/pkg/front_end/testcases/none/equals.dart b/pkg/front_end/testcases/none/equals.dart
new file mode 100644
index 0000000..8a5100f
--- /dev/null
+++ b/pkg/front_end/testcases/none/equals.dart
@@ -0,0 +1,370 @@
+// 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.md file.
+
+const Object? nullValue = null;
+
+class Class<T> {
+  operator ==(covariant Class<T> other) => true;
+
+  method(o) {}
+}
+
+test<T1 extends Function, T2 extends int Function(int)>(
+    Object o,
+    Object nonNullableObject,
+    Object? nullableObject,
+    Class<String> nonNullableClass,
+    Class<String>? nullableClass,
+    dynamic dyn,
+    Never never,
+    Never? nullableNever,
+    Null nullTypedValue,
+    Function nonNullableFunction,
+    Function? nullableFunction,
+    int Function(int) nonNullableFunctionType,
+    int Function(int)? nullableFunctionType,
+    T1 nonNullableTypeVariable1,
+    T1? nullableTypeVariable1,
+    T2 nonNullableTypeVariable2,
+    T2? nullableTypeVariable2) {
+  print('EqualsNull (literal null)');
+  null == null;
+  null != null;
+
+  nonNullableObject == null;
+  nonNullableObject != null;
+  null == nonNullableObject;
+  null != nonNullableObject;
+
+  nullableObject == null;
+  nullableObject != null;
+  null == nullableObject;
+  null != nullableObject;
+
+  nullableClass == null;
+  nullableClass != null;
+  null == nullableClass;
+  null != nullableClass;
+
+  nonNullableClass == null;
+  nonNullableClass != null;
+  null == nonNullableClass;
+  null != nonNullableClass;
+
+  dyn == null;
+  dyn != null;
+  null == dyn;
+  null != dyn;
+
+  never == null;
+  never != null;
+  null == never;
+  null != never;
+
+  nullableNever == null;
+  nullableNever != null;
+  null == nullableNever;
+  null != nullableNever;
+
+  nullTypedValue == null;
+  nullTypedValue != null;
+  null == nullTypedValue;
+  null != nullTypedValue;
+
+  nonNullableFunction == null;
+  nonNullableFunction != null;
+  null == nonNullableFunction;
+  null != nonNullableFunction;
+
+  nullableFunction == null;
+  nullableFunction != null;
+  null == nullableFunction;
+  null != nullableFunction;
+
+  nonNullableFunctionType == null;
+  nonNullableFunctionType != null;
+  null == nonNullableFunctionType;
+  null != nonNullableFunctionType;
+
+  nullableFunctionType == null;
+  nullableFunctionType != null;
+  null == nullableFunctionType;
+  null != nullableFunctionType;
+
+  nonNullableTypeVariable1 == null;
+  nonNullableTypeVariable1 != null;
+  null == nonNullableTypeVariable1;
+  null != nonNullableTypeVariable1;
+
+  nullableTypeVariable1 == null;
+  nullableTypeVariable1 != null;
+  null == nullableTypeVariable1;
+  null != nullableTypeVariable1;
+
+  nonNullableTypeVariable2 == null;
+  nonNullableTypeVariable2 != null;
+  null == nonNullableTypeVariable2;
+  null != nonNullableTypeVariable2;
+
+  nullableTypeVariable2 == null;
+  nullableTypeVariable2 != null;
+  null == nullableTypeVariable2;
+  null != nullableTypeVariable2;
+
+  nonNullableClass.method() == null;
+  nonNullableClass.method() != null;
+  null == nonNullableClass.method();
+  null != nonNullableClass.method();
+
+  print('EqualsNull (constant null)');
+  nullValue == nullValue;
+  nullValue != nullValue;
+
+  nonNullableObject == nullValue;
+  nonNullableObject != nullValue;
+  nullValue == nonNullableObject;
+  nullValue != nonNullableObject;
+
+  nullableObject == nullValue;
+  nullableObject != nullValue;
+  nullValue == nullableObject;
+  nullValue != nullableObject;
+
+  nonNullableClass == nullValue;
+  nonNullableClass != nullValue;
+  nullValue == nonNullableClass;
+  nullValue != nonNullableClass;
+
+  nullableClass == nullValue;
+  nullableClass != nullValue;
+  nullValue == nullableClass;
+  nullValue != nullableClass;
+
+  dyn == nullValue;
+  dyn != nullValue;
+  nullValue == dyn;
+  nullValue != dyn;
+
+  never == nullValue;
+  never != nullValue;
+  nullValue == never;
+  nullValue != never;
+
+  nullableNever == nullValue;
+  nullableNever != nullValue;
+  nullValue == nullableNever;
+  nullValue != nullableNever;
+
+  nullTypedValue == nullValue;
+  nullTypedValue != nullValue;
+  nullValue == nullTypedValue;
+  nullValue != nullTypedValue;
+
+  nonNullableFunction == nullValue;
+  nonNullableFunction != nullValue;
+  nullValue == nonNullableFunction;
+  nullValue != nonNullableFunction;
+
+  nullableFunction == nullValue;
+  nullableFunction != nullValue;
+  nullValue == nullableFunction;
+  nullValue != nullableFunction;
+
+  nonNullableFunctionType == nullValue;
+  nonNullableFunctionType != nullValue;
+  nullValue == nonNullableFunctionType;
+  nullValue != nonNullableFunctionType;
+
+  nullableFunctionType == nullValue;
+  nullableFunctionType != nullValue;
+  nullValue == nullableFunctionType;
+  nullValue != nullableFunctionType;
+
+  nonNullableTypeVariable1 == nullValue;
+  nonNullableTypeVariable1 != nullValue;
+  nullValue == nonNullableTypeVariable1;
+  nullValue != nonNullableTypeVariable1;
+
+  nullableTypeVariable1 == nullValue;
+  nullableTypeVariable1 != nullValue;
+  nullValue == nullableTypeVariable1;
+  nullValue != nullableTypeVariable1;
+
+  nonNullableTypeVariable2 == nullValue;
+  nonNullableTypeVariable2 != nullValue;
+  nullValue == nonNullableTypeVariable2;
+  nullValue != nonNullableTypeVariable2;
+
+  nullableTypeVariable2 == nullValue;
+  nullableTypeVariable2 != nullValue;
+  nullValue == nullableTypeVariable2;
+  nullValue != nullableTypeVariable2;
+
+  nonNullableClass.method() == nullValue;
+  nonNullableClass.method() != nullValue;
+  nullValue == nonNullableClass.method();
+  nullValue != nonNullableClass.method();
+
+  print('EqualsCall');
+
+  nonNullableObject == nullTypedValue;
+  nonNullableObject != nullTypedValue;
+  nullTypedValue == nonNullableObject;
+  nullTypedValue != nonNullableObject;
+  nonNullableObject == o;
+  nonNullableObject != o;
+  o == nonNullableObject;
+  o != nonNullableObject;
+
+  nullableObject == nullTypedValue;
+  nullableObject != nullTypedValue;
+  nullTypedValue == nullableObject;
+  nullTypedValue != nullableObject;
+  nullableObject == o;
+  nullableObject != o;
+  o == nullableObject;
+  o != nullableObject;
+
+  nonNullableClass == nullTypedValue;
+  nonNullableClass != nullTypedValue;
+  nullTypedValue == nonNullableClass;
+  nullTypedValue != nonNullableClass;
+  nonNullableClass == o;
+  nonNullableClass != o;
+  o == nonNullableClass;
+  o != nonNullableClass;
+
+  nullableClass == nullTypedValue;
+  nullableClass != nullTypedValue;
+  nullTypedValue == nullableClass;
+  nullTypedValue != nullableClass;
+  nullableClass == o;
+  nullableClass != o;
+  o == nullableClass;
+  o != nullableClass;
+
+  dyn == nullTypedValue;
+  dyn != nullTypedValue;
+  nullTypedValue == dyn;
+  nullTypedValue != dyn;
+  dyn == o;
+  dyn != o;
+  o == dyn;
+  o != dyn;
+
+  never == nullTypedValue;
+  never != nullTypedValue;
+  nullTypedValue == never;
+  nullTypedValue != never;
+  never == o;
+  never != o;
+  o == never;
+  o != never;
+
+  nullableNever == nullTypedValue;
+  nullableNever != nullTypedValue;
+  nullTypedValue == nullableNever;
+  nullTypedValue != nullableNever;
+  nullableNever == o;
+  nullableNever != o;
+  o == nullableNever;
+  o != nullableNever;
+
+  nullTypedValue == nullTypedValue;
+  nullTypedValue != nullTypedValue;
+  nullTypedValue == nullTypedValue;
+  nullTypedValue != nullTypedValue;
+  nullTypedValue == o;
+  nullTypedValue != o;
+  o == nullTypedValue;
+  o != nullTypedValue;
+
+  nonNullableFunction == nullTypedValue;
+  nonNullableFunction != nullTypedValue;
+  nullTypedValue == nonNullableFunction;
+  nullTypedValue != nonNullableFunction;
+  nonNullableFunction == o;
+  nonNullableFunction != o;
+  o == nonNullableFunction;
+  o != nonNullableFunction;
+
+  nullableFunction == nullTypedValue;
+  nullableFunction != nullTypedValue;
+  nullTypedValue == nullableFunction;
+  nullTypedValue != nullableFunction;
+  nullableFunction == o;
+  nullableFunction != o;
+  o == nullableFunction;
+  o != nullableFunction;
+
+  nonNullableFunctionType == nullTypedValue;
+  nonNullableFunctionType != nullTypedValue;
+  nullTypedValue == nonNullableFunctionType;
+  nullTypedValue != nonNullableFunctionType;
+  nonNullableFunctionType == o;
+  nonNullableFunctionType != o;
+  o == nonNullableFunctionType;
+  o != nonNullableFunctionType;
+
+  nullableFunctionType == nullTypedValue;
+  nullableFunctionType != nullTypedValue;
+  nullTypedValue == nullableFunctionType;
+  nullTypedValue != nullableFunctionType;
+  nullableFunctionType == o;
+  nullableFunctionType != o;
+  o == nullableFunctionType;
+  o != nullableFunctionType;
+
+  nonNullableTypeVariable1 == nullTypedValue;
+  nonNullableTypeVariable1 != nullTypedValue;
+  nullTypedValue == nonNullableTypeVariable1;
+  nullTypedValue != nonNullableTypeVariable1;
+  nonNullableTypeVariable1 == o;
+  nonNullableTypeVariable1 != o;
+  o == nonNullableTypeVariable1;
+  o != nonNullableTypeVariable1;
+
+  nullableTypeVariable1 == nullTypedValue;
+  nullableTypeVariable1 != nullTypedValue;
+  nullTypedValue == nullableTypeVariable1;
+  nullTypedValue != nullableTypeVariable1;
+  nullableTypeVariable1 == o;
+  nullableTypeVariable1 != o;
+  o == nullableTypeVariable1;
+  o != nullableTypeVariable1;
+
+  nonNullableTypeVariable2 == nullTypedValue;
+  nonNullableTypeVariable2 != nullTypedValue;
+  nullTypedValue == nonNullableTypeVariable2;
+  nullTypedValue != nonNullableTypeVariable2;
+  nonNullableTypeVariable2 == o;
+  nonNullableTypeVariable2 != o;
+  o == nonNullableTypeVariable2;
+  o != nonNullableTypeVariable2;
+
+  nullableTypeVariable2 == nullTypedValue;
+  nullableTypeVariable2 != nullTypedValue;
+  nullTypedValue == nullableTypeVariable2;
+  nullTypedValue != nullableTypeVariable2;
+  nullableTypeVariable2 == o;
+  nullableTypeVariable2 != o;
+  o == nullableTypeVariable2;
+  o != nullableTypeVariable2;
+
+  nonNullableClass.method() == nullTypedValue;
+  nonNullableClass.method() != nullTypedValue;
+  nullTypedValue == nonNullableClass.method();
+  nullTypedValue != nonNullableClass.method();
+  nonNullableClass.method() == o;
+  nonNullableClass.method() != o;
+  o == nonNullableClass.method();
+  o != nonNullableClass.method();
+}
+
+nullEqualsIndexGet(Map<int, String> map) {
+  null == map[0];
+  map[0] == null;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/none/equals.dart.outline.expect b/pkg/front_end/testcases/none/equals.dart.outline.expect
new file mode 100644
index 0000000..aae3b91
--- /dev/null
+++ b/pkg/front_end/testcases/none/equals.dart.outline.expect
@@ -0,0 +1,19 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T%>
+    ;
+  operator ==(covariant generic-covariant-impl self::Class<self::Class::T%> other) → core::bool
+    ;
+  method method(dynamic o) → dynamic
+    ;
+}
+static const field core::Object? nullValue = null;
+static method test<T1 extends core::Function = core::Function, T2 extends (core::int) → core::int = (core::int) → core::int>(core::Object o, core::Object nonNullableObject, core::Object? nullableObject, self::Class<core::String> nonNullableClass, self::Class<core::String>? nullableClass, dynamic dyn, Never never, Never? nullableNever, Null nullTypedValue, core::Function nonNullableFunction, core::Function? nullableFunction, (core::int) → core::int nonNullableFunctionType, (core::int) →? core::int nullableFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2) → dynamic
+  ;
+static method nullEqualsIndexGet(core::Map<core::int, core::String> map) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/none/equals.dart.strong.expect b/pkg/front_end/testcases/none/equals.dart.strong.expect
new file mode 100644
index 0000000..61c94f5
--- /dev/null
+++ b/pkg/front_end/testcases/none/equals.dart.strong.expect
@@ -0,0 +1,482 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/equals.dart:115:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() == null;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:116:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() != null;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:117:34: Error: Too few positional arguments: 1 required, 0 given.
+//   null == nonNullableClass.method();
+//                                  ^
+//
+// pkg/front_end/testcases/none/equals.dart:118:34: Error: Too few positional arguments: 1 required, 0 given.
+//   null != nonNullableClass.method();
+//                                  ^
+//
+// pkg/front_end/testcases/none/equals.dart:134:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nonNullableClass == nullValue;
+//                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:135:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nonNullableClass != nullValue;
+//                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:139:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nullableClass == nullValue;
+//                    ^
+//
+// pkg/front_end/testcases/none/equals.dart:140:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nullableClass != nullValue;
+//                    ^
+//
+// pkg/front_end/testcases/none/equals.dart:204:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() == nullValue;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:205:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() != nullValue;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:206:39: Error: Too few positional arguments: 1 required, 0 given.
+//   nullValue == nonNullableClass.method();
+//                                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:207:39: Error: Too few positional arguments: 1 required, 0 given.
+//   nullValue != nonNullableClass.method();
+//                                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:233:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nonNullableClass == o;
+//                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:234:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nonNullableClass != o;
+//                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:242:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nullableClass == o;
+//                    ^
+//
+// pkg/front_end/testcases/none/equals.dart:243:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nullableClass != o;
+//                    ^
+//
+// pkg/front_end/testcases/none/equals.dart:355:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() == nullTypedValue;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:356:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() != nullTypedValue;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:357:44: Error: Too few positional arguments: 1 required, 0 given.
+//   nullTypedValue == nonNullableClass.method();
+//                                            ^
+//
+// pkg/front_end/testcases/none/equals.dart:358:44: Error: Too few positional arguments: 1 required, 0 given.
+//   nullTypedValue != nonNullableClass.method();
+//                                            ^
+//
+// pkg/front_end/testcases/none/equals.dart:359:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() == o;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:360:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() != o;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:361:31: Error: Too few positional arguments: 1 required, 0 given.
+//   o == nonNullableClass.method();
+//                               ^
+//
+// pkg/front_end/testcases/none/equals.dart:362:31: Error: Too few positional arguments: 1 required, 0 given.
+//   o != nonNullableClass.method();
+//                               ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T%>
+    : super core::Object::•()
+    ;
+  operator ==(covariant generic-covariant-impl self::Class<self::Class::T%> other) → core::bool
+    return true;
+  method method(dynamic o) → dynamic {}
+}
+static const field core::Object? nullValue = #C1;
+static method test<T1 extends core::Function = core::Function, T2 extends (core::int) → core::int = (core::int) → core::int>(core::Object o, core::Object nonNullableObject, core::Object? nullableObject, self::Class<core::String> nonNullableClass, self::Class<core::String>? nullableClass, dynamic dyn, Never never, Never? nullableNever, Null nullTypedValue, core::Function nonNullableFunction, core::Function? nullableFunction, (core::int) → core::int nonNullableFunctionType, (core::int) →? core::int nullableFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2) → dynamic {
+  core::print("EqualsNull (literal null)");
+  null == null;
+  null != null;
+  nonNullableObject == null;
+  nonNullableObject != null;
+  nonNullableObject == null;
+  nonNullableObject != null;
+  nullableObject == null;
+  nullableObject != null;
+  nullableObject == null;
+  nullableObject != null;
+  nullableClass == null;
+  nullableClass != null;
+  nullableClass == null;
+  nullableClass != null;
+  nonNullableClass == null;
+  nonNullableClass != null;
+  nonNullableClass == null;
+  nonNullableClass != null;
+  dyn == null;
+  dyn != null;
+  dyn == null;
+  dyn != null;
+  never == null;
+  never != null;
+  never == null;
+  never != null;
+  nullableNever == null;
+  nullableNever != null;
+  nullableNever == null;
+  nullableNever != null;
+  nullTypedValue == null;
+  nullTypedValue != null;
+  nullTypedValue == null;
+  nullTypedValue != null;
+  nonNullableFunction == null;
+  nonNullableFunction != null;
+  nonNullableFunction == null;
+  nonNullableFunction != null;
+  nullableFunction == null;
+  nullableFunction != null;
+  nullableFunction == null;
+  nullableFunction != null;
+  nonNullableFunctionType == null;
+  nonNullableFunctionType != null;
+  nonNullableFunctionType == null;
+  nonNullableFunctionType != null;
+  nullableFunctionType == null;
+  nullableFunctionType != null;
+  nullableFunctionType == null;
+  nullableFunctionType != null;
+  nonNullableTypeVariable1 == null;
+  nonNullableTypeVariable1 != null;
+  nonNullableTypeVariable1 == null;
+  nonNullableTypeVariable1 != null;
+  nullableTypeVariable1 == null;
+  nullableTypeVariable1 != null;
+  nullableTypeVariable1 == null;
+  nullableTypeVariable1 != null;
+  nonNullableTypeVariable2 == null;
+  nonNullableTypeVariable2 != null;
+  nonNullableTypeVariable2 == null;
+  nonNullableTypeVariable2 != null;
+  nullableTypeVariable2 == null;
+  nullableTypeVariable2 != null;
+  nullableTypeVariable2 == null;
+  nullableTypeVariable2 != null;
+  (let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/none/equals.dart:115:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() == null;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
+  (let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/none/equals.dart:116:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() != null;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+  (let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/none/equals.dart:117:34: Error: Too few positional arguments: 1 required, 0 given.
+  null == nonNullableClass.method();
+                                 ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
+  (let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/none/equals.dart:118:34: Error: Too few positional arguments: 1 required, 0 given.
+  null != nonNullableClass.method();
+                                 ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+  core::print("EqualsNull (constant null)");
+  (#C1) == null;
+  (#C1) != null;
+  nonNullableObject == null;
+  nonNullableObject != null;
+  nonNullableObject == null;
+  nonNullableObject != null;
+  nullableObject == null;
+  nullableObject != null;
+  nullableObject == null;
+  nullableObject != null;
+  nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t5 = invalid-expression "pkg/front_end/testcases/none/equals.dart:134:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nonNullableClass == nullValue;
+                      ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t6 = invalid-expression "pkg/front_end/testcases/none/equals.dart:135:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nonNullableClass != nullValue;
+                      ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nonNullableClass == null;
+  nonNullableClass != null;
+  nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t7 = invalid-expression "pkg/front_end/testcases/none/equals.dart:139:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nullableClass == nullValue;
+                   ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/none/equals.dart:140:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nullableClass != nullValue;
+                   ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nullableClass == null;
+  nullableClass != null;
+  dyn == null;
+  dyn != null;
+  dyn == null;
+  dyn != null;
+  never == null;
+  never != null;
+  never == null;
+  never != null;
+  nullableNever == null;
+  nullableNever != null;
+  nullableNever == null;
+  nullableNever != null;
+  nullTypedValue == null;
+  nullTypedValue != null;
+  nullTypedValue == null;
+  nullTypedValue != null;
+  nonNullableFunction == null;
+  nonNullableFunction != null;
+  nonNullableFunction == null;
+  nonNullableFunction != null;
+  nullableFunction == null;
+  nullableFunction != null;
+  nullableFunction == null;
+  nullableFunction != null;
+  nonNullableFunctionType == null;
+  nonNullableFunctionType != null;
+  nonNullableFunctionType == null;
+  nonNullableFunctionType != null;
+  nullableFunctionType == null;
+  nullableFunctionType != null;
+  nullableFunctionType == null;
+  nullableFunctionType != null;
+  nonNullableTypeVariable1 == null;
+  nonNullableTypeVariable1 != null;
+  nonNullableTypeVariable1 == null;
+  nonNullableTypeVariable1 != null;
+  nullableTypeVariable1 == null;
+  nullableTypeVariable1 != null;
+  nullableTypeVariable1 == null;
+  nullableTypeVariable1 != null;
+  nonNullableTypeVariable2 == null;
+  nonNullableTypeVariable2 != null;
+  nonNullableTypeVariable2 == null;
+  nonNullableTypeVariable2 != null;
+  nullableTypeVariable2 == null;
+  nullableTypeVariable2 != null;
+  nullableTypeVariable2 == null;
+  nullableTypeVariable2 != null;
+  (let final<BottomType> #t9 = invalid-expression "pkg/front_end/testcases/none/equals.dart:204:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() == nullValue;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
+  (let final<BottomType> #t10 = invalid-expression "pkg/front_end/testcases/none/equals.dart:205:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() != nullValue;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+  (let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/none/equals.dart:206:39: Error: Too few positional arguments: 1 required, 0 given.
+  nullValue == nonNullableClass.method();
+                                      ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
+  (let final<BottomType> #t12 = invalid-expression "pkg/front_end/testcases/none/equals.dart:207:39: Error: Too few positional arguments: 1 required, 0 given.
+  nullValue != nonNullableClass.method();
+                                      ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+  core::print("EqualsCall");
+  nonNullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableObject !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  nonNullableObject =={core::Object::==}{(core::Object) → core::bool} o;
+  nonNullableObject !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  nullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableObject !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  nullableObject =={core::Object::==}{(core::Object) → core::bool} o;
+  nullableObject !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t13 = invalid-expression "pkg/front_end/testcases/none/equals.dart:233:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nonNullableClass == o;
+                      ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t14 = invalid-expression "pkg/front_end/testcases/none/equals.dart:234:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nonNullableClass != o;
+                      ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t15 = invalid-expression "pkg/front_end/testcases/none/equals.dart:242:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nullableClass == o;
+                   ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t16 = invalid-expression "pkg/front_end/testcases/none/equals.dart:243:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nullableClass != o;
+                   ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  o =={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  dyn =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  dyn !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} dyn;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} dyn;
+  dyn =={core::Object::==}{(core::Object) → core::bool} o;
+  dyn !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} dyn;
+  o !={core::Object::==}{(core::Object) → core::bool} dyn;
+  never =={core::Object::==}{(dynamic) → Never} nullTypedValue;
+  never !={core::Object::==}{(dynamic) → Never} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} never;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} never;
+  never =={core::Object::==}{(dynamic) → Never} o;
+  never !={core::Object::==}{(dynamic) → Never} o;
+  o =={core::Object::==}{(core::Object) → core::bool} never;
+  o !={core::Object::==}{(core::Object) → core::bool} never;
+  nullableNever =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableNever !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  nullableNever =={core::Object::==}{(core::Object) → core::bool} o;
+  nullableNever !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} o;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  o !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableFunction !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} o;
+  nonNullableFunction !={core::Function::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  nullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableFunction !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  nullableFunction =={core::Function::==}{(core::Object) → core::bool} o;
+  nullableFunction !={core::Function::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableFunctionType !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o;
+  nonNullableFunctionType !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableFunctionType !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o;
+  nullableFunctionType !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o;
+  nonNullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o;
+  nullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o;
+  nonNullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o;
+  nullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  (let final<BottomType> #t17 = invalid-expression "pkg/front_end/testcases/none/equals.dart:355:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() == nullTypedValue;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  (let final<BottomType> #t18 = invalid-expression "pkg/front_end/testcases/none/equals.dart:356:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() != nullTypedValue;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} (let final<BottomType> #t19 = invalid-expression "pkg/front_end/testcases/none/equals.dart:357:44: Error: Too few positional arguments: 1 required, 0 given.
+  nullTypedValue == nonNullableClass.method();
+                                           ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} (let final<BottomType> #t20 = invalid-expression "pkg/front_end/testcases/none/equals.dart:358:44: Error: Too few positional arguments: 1 required, 0 given.
+  nullTypedValue != nonNullableClass.method();
+                                           ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+  (let final<BottomType> #t21 = invalid-expression "pkg/front_end/testcases/none/equals.dart:359:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() == o;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} o;
+  (let final<BottomType> #t22 = invalid-expression "pkg/front_end/testcases/none/equals.dart:360:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() != o;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} (let final<BottomType> #t23 = invalid-expression "pkg/front_end/testcases/none/equals.dart:361:31: Error: Too few positional arguments: 1 required, 0 given.
+  o == nonNullableClass.method();
+                              ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+  o !={core::Object::==}{(core::Object) → core::bool} (let final<BottomType> #t24 = invalid-expression "pkg/front_end/testcases/none/equals.dart:362:31: Error: Too few positional arguments: 1 required, 0 given.
+  o != nonNullableClass.method();
+                              ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+}
+static method nullEqualsIndexGet(core::Map<core::int, core::String> map) → dynamic {
+  map.{core::Map::[]}(0){(core::Object?) → core::String?} == null;
+  map.{core::Map::[]}(0){(core::Object?) → core::String?} == null;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/none/equals.dart.textual_outline.expect b/pkg/front_end/testcases/none/equals.dart.textual_outline.expect
new file mode 100644
index 0000000..bd43417
--- /dev/null
+++ b/pkg/front_end/testcases/none/equals.dart.textual_outline.expect
@@ -0,0 +1,27 @@
+const Object? nullValue = null;
+
+class Class<T> {
+  operator ==(covariant Class<T> other) => true;
+  method(o) {}
+}
+
+test<T1 extends Function, T2 extends int Function(int)>(
+    Object o,
+    Object nonNullableObject,
+    Object? nullableObject,
+    Class<String> nonNullableClass,
+    Class<String>? nullableClass,
+    dynamic dyn,
+    Never never,
+    Never? nullableNever,
+    Null nullTypedValue,
+    Function nonNullableFunction,
+    Function? nullableFunction,
+    int Function(int) nonNullableFunctionType,
+    int Function(int)? nullableFunctionType,
+    T1 nonNullableTypeVariable1,
+    T1? nullableTypeVariable1,
+    T2 nonNullableTypeVariable2,
+    T2? nullableTypeVariable2) {}
+nullEqualsIndexGet(Map<int, String> map) {}
+main() {}
diff --git a/pkg/front_end/testcases/none/equals.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/none/equals.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..58ef786
--- /dev/null
+++ b/pkg/front_end/testcases/none/equals.dart.textual_outline_modelled.expect
@@ -0,0 +1,26 @@
+class Class<T> {
+  method(o) {}
+  operator ==(covariant Class<T> other) => true;
+}
+
+const Object? nullValue = null;
+main() {}
+nullEqualsIndexGet(Map<int, String> map) {}
+test<T1 extends Function, T2 extends int Function(int)>(
+    Object o,
+    Object nonNullableObject,
+    Object? nullableObject,
+    Class<String> nonNullableClass,
+    Class<String>? nullableClass,
+    dynamic dyn,
+    Never never,
+    Never? nullableNever,
+    Null nullTypedValue,
+    Function nonNullableFunction,
+    Function? nullableFunction,
+    int Function(int) nonNullableFunctionType,
+    int Function(int)? nullableFunctionType,
+    T1 nonNullableTypeVariable1,
+    T1? nullableTypeVariable1,
+    T2 nonNullableTypeVariable2,
+    T2? nullableTypeVariable2) {}
diff --git a/pkg/front_end/testcases/none/equals.dart.weak.expect b/pkg/front_end/testcases/none/equals.dart.weak.expect
new file mode 100644
index 0000000..11bf642
--- /dev/null
+++ b/pkg/front_end/testcases/none/equals.dart.weak.expect
@@ -0,0 +1,483 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/equals.dart:115:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() == null;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:116:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() != null;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:117:34: Error: Too few positional arguments: 1 required, 0 given.
+//   null == nonNullableClass.method();
+//                                  ^
+//
+// pkg/front_end/testcases/none/equals.dart:118:34: Error: Too few positional arguments: 1 required, 0 given.
+//   null != nonNullableClass.method();
+//                                  ^
+//
+// pkg/front_end/testcases/none/equals.dart:134:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nonNullableClass == nullValue;
+//                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:135:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nonNullableClass != nullValue;
+//                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:139:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nullableClass == nullValue;
+//                    ^
+//
+// pkg/front_end/testcases/none/equals.dart:140:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nullableClass != nullValue;
+//                    ^
+//
+// pkg/front_end/testcases/none/equals.dart:204:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() == nullValue;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:205:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() != nullValue;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:206:39: Error: Too few positional arguments: 1 required, 0 given.
+//   nullValue == nonNullableClass.method();
+//                                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:207:39: Error: Too few positional arguments: 1 required, 0 given.
+//   nullValue != nonNullableClass.method();
+//                                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:233:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nonNullableClass == o;
+//                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:234:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nonNullableClass != o;
+//                       ^
+//
+// pkg/front_end/testcases/none/equals.dart:242:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nullableClass == o;
+//                    ^
+//
+// pkg/front_end/testcases/none/equals.dart:243:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+//  - 'Object' is from 'dart:core'.
+//  - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+//   nullableClass != o;
+//                    ^
+//
+// pkg/front_end/testcases/none/equals.dart:355:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() == nullTypedValue;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:356:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() != nullTypedValue;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:357:44: Error: Too few positional arguments: 1 required, 0 given.
+//   nullTypedValue == nonNullableClass.method();
+//                                            ^
+//
+// pkg/front_end/testcases/none/equals.dart:358:44: Error: Too few positional arguments: 1 required, 0 given.
+//   nullTypedValue != nonNullableClass.method();
+//                                            ^
+//
+// pkg/front_end/testcases/none/equals.dart:359:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() == o;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:360:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass.method() != o;
+//                          ^
+//
+// pkg/front_end/testcases/none/equals.dart:361:31: Error: Too few positional arguments: 1 required, 0 given.
+//   o == nonNullableClass.method();
+//                               ^
+//
+// pkg/front_end/testcases/none/equals.dart:362:31: Error: Too few positional arguments: 1 required, 0 given.
+//   o != nonNullableClass.method();
+//                               ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T%>
+    : super core::Object::•()
+    ;
+  operator ==(covariant generic-covariant-impl self::Class<self::Class::T%> other) → core::bool
+    return true;
+  method method(dynamic o) → dynamic {}
+}
+static const field core::Object? nullValue = #C1;
+static method test<T1 extends core::Function = core::Function, T2 extends (core::int) → core::int = (core::int) → core::int>(core::Object o, core::Object nonNullableObject, core::Object? nullableObject, self::Class<core::String> nonNullableClass, self::Class<core::String>? nullableClass, dynamic dyn, Never never, Never? nullableNever, Null nullTypedValue, core::Function nonNullableFunction, core::Function? nullableFunction, (core::int) → core::int nonNullableFunctionType, (core::int) →? core::int nullableFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2) → dynamic {
+  core::print("EqualsNull (literal null)");
+  null == null;
+  null != null;
+  nonNullableObject == null;
+  nonNullableObject != null;
+  nonNullableObject == null;
+  nonNullableObject != null;
+  nullableObject == null;
+  nullableObject != null;
+  nullableObject == null;
+  nullableObject != null;
+  nullableClass == null;
+  nullableClass != null;
+  nullableClass == null;
+  nullableClass != null;
+  nonNullableClass == null;
+  nonNullableClass != null;
+  nonNullableClass == null;
+  nonNullableClass != null;
+  dyn == null;
+  dyn != null;
+  dyn == null;
+  dyn != null;
+  (let final Never #t1 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null;
+  (let final Never #t2 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) != null;
+  (let final Never #t3 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null;
+  (let final Never #t4 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) != null;
+  nullableNever == null;
+  nullableNever != null;
+  nullableNever == null;
+  nullableNever != null;
+  nullTypedValue == null;
+  nullTypedValue != null;
+  nullTypedValue == null;
+  nullTypedValue != null;
+  nonNullableFunction == null;
+  nonNullableFunction != null;
+  nonNullableFunction == null;
+  nonNullableFunction != null;
+  nullableFunction == null;
+  nullableFunction != null;
+  nullableFunction == null;
+  nullableFunction != null;
+  nonNullableFunctionType == null;
+  nonNullableFunctionType != null;
+  nonNullableFunctionType == null;
+  nonNullableFunctionType != null;
+  nullableFunctionType == null;
+  nullableFunctionType != null;
+  nullableFunctionType == null;
+  nullableFunctionType != null;
+  nonNullableTypeVariable1 == null;
+  nonNullableTypeVariable1 != null;
+  nonNullableTypeVariable1 == null;
+  nonNullableTypeVariable1 != null;
+  nullableTypeVariable1 == null;
+  nullableTypeVariable1 != null;
+  nullableTypeVariable1 == null;
+  nullableTypeVariable1 != null;
+  nonNullableTypeVariable2 == null;
+  nonNullableTypeVariable2 != null;
+  nonNullableTypeVariable2 == null;
+  nonNullableTypeVariable2 != null;
+  nullableTypeVariable2 == null;
+  nullableTypeVariable2 != null;
+  nullableTypeVariable2 == null;
+  nullableTypeVariable2 != null;
+  (let final<BottomType> #t5 = invalid-expression "pkg/front_end/testcases/none/equals.dart:115:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() == null;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
+  (let final<BottomType> #t6 = invalid-expression "pkg/front_end/testcases/none/equals.dart:116:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() != null;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+  (let final<BottomType> #t7 = invalid-expression "pkg/front_end/testcases/none/equals.dart:117:34: Error: Too few positional arguments: 1 required, 0 given.
+  null == nonNullableClass.method();
+                                 ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
+  (let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/none/equals.dart:118:34: Error: Too few positional arguments: 1 required, 0 given.
+  null != nonNullableClass.method();
+                                 ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+  core::print("EqualsNull (constant null)");
+  (#C1) == null;
+  (#C1) != null;
+  nonNullableObject == null;
+  nonNullableObject != null;
+  nonNullableObject == null;
+  nonNullableObject != null;
+  nullableObject == null;
+  nullableObject != null;
+  nullableObject == null;
+  nullableObject != null;
+  nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t9 = invalid-expression "pkg/front_end/testcases/none/equals.dart:134:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nonNullableClass == nullValue;
+                      ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t10 = invalid-expression "pkg/front_end/testcases/none/equals.dart:135:23: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nonNullableClass != nullValue;
+                      ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nonNullableClass == null;
+  nonNullableClass != null;
+  nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/none/equals.dart:139:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nullableClass == nullValue;
+                   ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t12 = invalid-expression "pkg/front_end/testcases/none/equals.dart:140:20: Error: The argument type 'Object?' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nullableClass != nullValue;
+                   ^" in (#C1) as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nullableClass == null;
+  nullableClass != null;
+  dyn == null;
+  dyn != null;
+  dyn == null;
+  dyn != null;
+  let final Never #t13 = (let final Never #t14 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  let final Never #t15 = (let final Never #t16 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) != null in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  (let final Never #t17 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) == null;
+  (let final Never #t18 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) != null;
+  nullableNever == null;
+  nullableNever != null;
+  nullableNever == null;
+  nullableNever != null;
+  nullTypedValue == null;
+  nullTypedValue != null;
+  nullTypedValue == null;
+  nullTypedValue != null;
+  nonNullableFunction == null;
+  nonNullableFunction != null;
+  nonNullableFunction == null;
+  nonNullableFunction != null;
+  nullableFunction == null;
+  nullableFunction != null;
+  nullableFunction == null;
+  nullableFunction != null;
+  nonNullableFunctionType == null;
+  nonNullableFunctionType != null;
+  nonNullableFunctionType == null;
+  nonNullableFunctionType != null;
+  nullableFunctionType == null;
+  nullableFunctionType != null;
+  nullableFunctionType == null;
+  nullableFunctionType != null;
+  nonNullableTypeVariable1 == null;
+  nonNullableTypeVariable1 != null;
+  nonNullableTypeVariable1 == null;
+  nonNullableTypeVariable1 != null;
+  nullableTypeVariable1 == null;
+  nullableTypeVariable1 != null;
+  nullableTypeVariable1 == null;
+  nullableTypeVariable1 != null;
+  nonNullableTypeVariable2 == null;
+  nonNullableTypeVariable2 != null;
+  nonNullableTypeVariable2 == null;
+  nonNullableTypeVariable2 != null;
+  nullableTypeVariable2 == null;
+  nullableTypeVariable2 != null;
+  nullableTypeVariable2 == null;
+  nullableTypeVariable2 != null;
+  (let final<BottomType> #t19 = invalid-expression "pkg/front_end/testcases/none/equals.dart:204:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() == nullValue;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
+  (let final<BottomType> #t20 = invalid-expression "pkg/front_end/testcases/none/equals.dart:205:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() != nullValue;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+  (let final<BottomType> #t21 = invalid-expression "pkg/front_end/testcases/none/equals.dart:206:39: Error: Too few positional arguments: 1 required, 0 given.
+  nullValue == nonNullableClass.method();
+                                      ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) == null;
+  (let final<BottomType> #t22 = invalid-expression "pkg/front_end/testcases/none/equals.dart:207:39: Error: Too few positional arguments: 1 required, 0 given.
+  nullValue != nonNullableClass.method();
+                                      ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) != null;
+  core::print("EqualsCall");
+  nonNullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableObject !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  nonNullableObject =={core::Object::==}{(core::Object) → core::bool} o;
+  nonNullableObject !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableObject;
+  nullableObject =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableObject !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  nullableObject =={core::Object::==}{(core::Object) → core::bool} o;
+  nullableObject !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableObject;
+  nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  nonNullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t23 = invalid-expression "pkg/front_end/testcases/none/equals.dart:233:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nonNullableClass == o;
+                      ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nonNullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t24 = invalid-expression "pkg/front_end/testcases/none/equals.dart:234:23: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nonNullableClass != o;
+                      ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableClass;
+  nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  nullableClass =={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t25 = invalid-expression "pkg/front_end/testcases/none/equals.dart:242:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nullableClass == o;
+                   ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  nullableClass !={self::Class::==}{(self::Class<core::String>) → core::bool} (let final<BottomType> #t26 = invalid-expression "pkg/front_end/testcases/none/equals.dart:243:20: Error: The argument type 'Object' can't be assigned to the parameter type 'Class<String>?'.
+ - 'Object' is from 'dart:core'.
+ - 'Class' is from 'pkg/front_end/testcases/none/equals.dart'.
+  nullableClass != o;
+                   ^" in o as{TypeError,ForNonNullableByDefault} self::Class<core::String>?);
+  o =={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableClass;
+  dyn =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  dyn !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} dyn;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} dyn;
+  dyn =={core::Object::==}{(core::Object) → core::bool} o;
+  dyn !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} dyn;
+  o !={core::Object::==}{(core::Object) → core::bool} dyn;
+  let final Never #t27 = (let final Never #t28 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) =={core::Object::==}{(dynamic) → Never} nullTypedValue in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  let final Never #t29 = (let final Never #t30 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) !={core::Object::==}{(dynamic) → Never} nullTypedValue in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} (let final Never #t31 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."));
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} (let final Never #t32 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."));
+  let final Never #t33 = (let final Never #t34 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) =={core::Object::==}{(dynamic) → Never} o in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  let final Never #t35 = (let final Never #t36 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")) !={core::Object::==}{(dynamic) → Never} o in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  o =={core::Object::==}{(core::Object) → core::bool} (let final Never #t37 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."));
+  o !={core::Object::==}{(core::Object) → core::bool} (let final Never #t38 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."));
+  nullableNever =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableNever !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  nullableNever =={core::Object::==}{(core::Object) → core::bool} o;
+  nullableNever !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableNever;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} o;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  o !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableFunction !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  nonNullableFunction =={core::Function::==}{(core::Object) → core::bool} o;
+  nonNullableFunction !={core::Function::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableFunction;
+  nullableFunction =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableFunction !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  nullableFunction =={core::Function::==}{(core::Object) → core::bool} o;
+  nullableFunction !={core::Function::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableFunction;
+  nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableFunctionType !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  nonNullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o;
+  nonNullableFunctionType !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableFunctionType;
+  nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableFunctionType !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  nullableFunctionType =={core::Object::==}{(core::Object) → core::bool} o;
+  nullableFunctionType !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableFunctionType;
+  nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  nonNullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o;
+  nonNullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable1;
+  nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  nullableTypeVariable1 =={core::Function::==}{(core::Object) → core::bool} o;
+  nullableTypeVariable1 !={core::Function::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable1;
+  nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nonNullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  nonNullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o;
+  nonNullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  o !={core::Object::==}{(core::Object) → core::bool} nonNullableTypeVariable2;
+  nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  nullableTypeVariable2 =={core::Object::==}{(core::Object) → core::bool} o;
+  nullableTypeVariable2 !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  o !={core::Object::==}{(core::Object) → core::bool} nullableTypeVariable2;
+  (let final<BottomType> #t39 = invalid-expression "pkg/front_end/testcases/none/equals.dart:355:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() == nullTypedValue;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  (let final<BottomType> #t40 = invalid-expression "pkg/front_end/testcases/none/equals.dart:356:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() != nullTypedValue;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) !={core::Object::==}{(core::Object) → core::bool} nullTypedValue;
+  nullTypedValue =={core::Object::==}{(core::Object) → core::bool} (let final<BottomType> #t41 = invalid-expression "pkg/front_end/testcases/none/equals.dart:357:44: Error: Too few positional arguments: 1 required, 0 given.
+  nullTypedValue == nonNullableClass.method();
+                                           ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+  nullTypedValue !={core::Object::==}{(core::Object) → core::bool} (let final<BottomType> #t42 = invalid-expression "pkg/front_end/testcases/none/equals.dart:358:44: Error: Too few positional arguments: 1 required, 0 given.
+  nullTypedValue != nonNullableClass.method();
+                                           ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+  (let final<BottomType> #t43 = invalid-expression "pkg/front_end/testcases/none/equals.dart:359:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() == o;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) =={core::Object::==}{(core::Object) → core::bool} o;
+  (let final<BottomType> #t44 = invalid-expression "pkg/front_end/testcases/none/equals.dart:360:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass.method() != o;
+                         ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type}) !={core::Object::==}{(core::Object) → core::bool} o;
+  o =={core::Object::==}{(core::Object) → core::bool} (let final<BottomType> #t45 = invalid-expression "pkg/front_end/testcases/none/equals.dart:361:31: Error: Too few positional arguments: 1 required, 0 given.
+  o == nonNullableClass.method();
+                              ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+  o !={core::Object::==}{(core::Object) → core::bool} (let final<BottomType> #t46 = invalid-expression "pkg/front_end/testcases/none/equals.dart:362:31: Error: Too few positional arguments: 1 required, 0 given.
+  o != nonNullableClass.method();
+                              ^" in nonNullableClass.{self::Class::method}{<inapplicable>}.(){() → invalid-type});
+}
+static method nullEqualsIndexGet(core::Map<core::int, core::String> map) → dynamic {
+  map.{core::Map::[]}(0){(core::Object?) → core::String?} == null;
+  map.{core::Map::[]}(0){(core::Object?) → core::String?} == null;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/none/method_invocation.dart b/pkg/front_end/testcases/none/method_invocation.dart
new file mode 100644
index 0000000..e354863
--- /dev/null
+++ b/pkg/front_end/testcases/none/method_invocation.dart
@@ -0,0 +1,161 @@
+// 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.md file.
+
+class Class1 {
+  double method(int o) => 0.5;
+}
+
+class Class2<T> {
+  T field;
+
+  Class2(this.field, this.nonNullableFunctionField,
+      this.nonNullableFunctionTypedField);
+
+  T call() => field;
+
+  T method(int o) => field;
+
+  Function nonNullableFunctionField;
+
+  Function get nonNullableFunctionGetter => nonNullableFunctionTypedField;
+
+  Function? nullableFunctionField;
+
+  Function? get nullableFunctionGetter => nonNullableFunctionTypedField;
+
+  void Function() nonNullableFunctionTypedField;
+
+  void Function() get nonNullableFunctionTypedGetter =>
+      nonNullableFunctionTypedField;
+
+  void Function()? nullableFunctionTypedField;
+
+  void Function()? get nullableFunctionTypedGetter =>
+      nonNullableFunctionTypedField;
+}
+
+const int i = 4;
+const int j = 24;
+const int k = i * j;
+
+test<T1 extends Function, T2 extends int Function(int), T3>(
+    Class1 nonNullableClass1,
+    Class1? nullableClass1,
+    dynamic dyn,
+    Never never,
+    Class2<String> nonNullableClass2,
+    Class2<String>? nullableClass2,
+    Function nonNullableFunction,
+    Function? nullableFunction,
+    int Function(int) nonNullableFunctionType,
+    int Function(int)? nullableFunctionType,
+    T Function<T>(T) genericFunctionType,
+    T1 nonNullableTypeVariable1,
+    T1? nullableTypeVariable1,
+    T2 nonNullableTypeVariable2,
+    T2? nullableTypeVariable2,
+    T3 undeterminedTypeVariable) {
+  print('InstanceInvocation');
+  nonNullableClass1.method(0);
+  nullableClass1?.method(0);
+
+  print('InstanceGet calls');
+  nonNullableClass2.nonNullableFunctionField();
+  nonNullableClass2.nonNullableFunctionGetter();
+  nonNullableClass2.nonNullableFunctionTypedField();
+  nonNullableClass2.nonNullableFunctionTypedGetter();
+  nonNullableClass2.nullableFunctionField();
+  nonNullableClass2.nullableFunctionGetter();
+  nonNullableClass2.nullableFunctionTypedField();
+  nonNullableClass2.nullableFunctionTypedGetter();
+  nonNullableClass2.nonNullableFunctionField(0);
+  nonNullableClass2.nonNullableFunctionGetter(0);
+  nonNullableClass2.nonNullableFunctionTypedField(0);
+  nonNullableClass2.nonNullableFunctionTypedGetter(0);
+
+  print('InstanceInvocation (Nullable)');
+  nullableClass1.method(0);
+
+  print('DynamicInvocation');
+  dyn.method(0);
+  dyn?.method(0);
+  dyn.toString(0);
+  const int call_dyn = dyn.toString(0);
+  print(call_dyn);
+
+  print('InstanceInvocation (Object)');
+  dyn.toString();
+  nullableClass1.toString();
+  nullableClass2.toString();
+  nullableFunction.toString();
+  nullableFunctionType.toString();
+  nullableTypeVariable1.toString();
+  nullableTypeVariable2.toString();
+  undeterminedTypeVariable.toString();
+
+  print('DynamicInvocation (Never)');
+  never.method(0);
+  never.toString();
+
+  print('DynamicInvocation (Unresolved)');
+  nonNullableClass1.unresolved();
+
+  print('DynamicInvocation (Inapplicable)');
+  nonNullableClass1.method();
+  nonNullableFunctionType();
+
+  print('InstanceInvocation (generic)');
+  nonNullableClass2.method(0);
+  nullableClass2?.method(0);
+  nonNullableClass2();
+  nonNullableClass2.call();
+
+  print('FunctionInvocation');
+  nonNullableFunction(0);
+  nonNullableFunction.call(0);
+  nullableFunction?.call(0);
+  nonNullableFunctionType(0);
+  nonNullableFunctionType.call(0);
+  nullableFunctionType?.call(0);
+  genericFunctionType(0);
+  genericFunctionType<num>(0);
+  num i = genericFunctionType(0);
+  nonNullableTypeVariable1(0);
+  nonNullableTypeVariable1.call(0);
+  nullableTypeVariable1?.call(0);
+  nonNullableTypeVariable2(0);
+  nonNullableTypeVariable2.call(0);
+  nullableTypeVariable2?.call(0);
+
+  print('FunctionInvocation (Nullable)');
+  nullableFunction(0);
+  nullableFunction.call(0);
+  nullableFunctionType(0);
+  nullableFunctionType.call(0);
+
+  print('DynamicInvocation (Invalid)');
+  nonNullableClass1.method().method(0);
+
+  print('LocalFunctionInvocation');
+  int localFunction() => 42;
+  T genericLocalFunction<T>(T t) => t;
+  localFunction();
+  genericLocalFunction(0);
+  genericLocalFunction<num>(0);
+
+  const int call_localFunction = localFunction();
+  print(call_localFunction);
+
+  int Function() f = () => 42;
+
+  const int call_f = f();
+  print(call_f);
+  const int? nullable = 0;
+  const bool equals_null = nullable == null;
+  print(equals_null);
+  const bool equals = i == j;
+  print(equals);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/none/method_invocation.dart.outline.expect b/pkg/front_end/testcases/none/method_invocation.dart.outline.expect
new file mode 100644
index 0000000..8a7fc69
--- /dev/null
+++ b/pkg/front_end/testcases/none/method_invocation.dart.outline.expect
@@ -0,0 +1,43 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → self::Class1
+    ;
+  method method(core::int o) → core::double
+    ;
+}
+class Class2<T extends core::Object? = dynamic> extends core::Object {
+  generic-covariant-impl field self::Class2::T% field;
+  field core::Function nonNullableFunctionField;
+  field core::Function? nullableFunctionField;
+  field () → void nonNullableFunctionTypedField;
+  field () →? void nullableFunctionTypedField;
+  constructor •(self::Class2::T% field, core::Function nonNullableFunctionField, () → void nonNullableFunctionTypedField) → self::Class2<self::Class2::T%>
+    ;
+  method call() → self::Class2::T%
+    ;
+  method method(core::int o) → self::Class2::T%
+    ;
+  get nonNullableFunctionGetter() → core::Function
+    ;
+  get nullableFunctionGetter() → core::Function?
+    ;
+  get nonNullableFunctionTypedGetter() → () → void
+    ;
+  get nullableFunctionTypedGetter() → () →? void
+    ;
+}
+static const field core::int i = 4;
+static const field core::int j = 24;
+static const field core::int k = self::i.{core::num::*}(self::j){(core::num) → core::int};
+static method test<T1 extends core::Function = core::Function, T2 extends (core::int) → core::int = (core::int) → core::int, T3 extends core::Object? = dynamic>(self::Class1 nonNullableClass1, self::Class1? nullableClass1, dynamic dyn, Never never, self::Class2<core::String> nonNullableClass2, self::Class2<core::String>? nullableClass2, core::Function nonNullableFunction, core::Function? nullableFunction, (core::int) → core::int nonNullableFunctionType, (core::int) →? core::int nullableFunctionType, <T extends core::Object? = dynamic>(T%) → T% genericFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2, self::test::T3% undeterminedTypeVariable) → dynamic
+  ;
+static method main() → dynamic
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///method_invocation.dart:40:17 -> IntConstant(96)
+Extra constant evaluation: evaluated: 1, effectively constant: 1
diff --git a/pkg/front_end/testcases/none/method_invocation.dart.strong.expect b/pkg/front_end/testcases/none/method_invocation.dart.strong.expect
new file mode 100644
index 0000000..d4e8da9
--- /dev/null
+++ b/pkg/front_end/testcases/none/method_invocation.dart.strong.expect
@@ -0,0 +1,296 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/method_invocation.dart:84:24: Error: Not a constant expression.
+//   const int call_dyn = dyn.toString(0);
+//                        ^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:84:28: Error: Method invocation is not a constant expression.
+//   const int call_dyn = dyn.toString(0);
+//                            ^^^^^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:147:34: Error: Not a constant expression.
+//   const int call_localFunction = localFunction();
+//                                  ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:152:22: Error: Not a constant expression.
+//   const int call_f = f();
+//                      ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:157:23: Error: Not a constant expression.
+//   const bool equals = i == j;
+//                       ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:68:42: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+//  - 'Function' is from 'dart:core'.
+// Try calling using ?.call instead.
+//   nonNullableClass2.nullableFunctionField();
+//                                          ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:69:43: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+//  - 'Function' is from 'dart:core'.
+// Try calling using ?.call instead.
+//   nonNullableClass2.nullableFunctionGetter();
+//                                           ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:70:47: Error: Can't use an expression of type 'void Function()?' as a function because it's potentially null.
+// Try calling using ?.call instead.
+//   nonNullableClass2.nullableFunctionTypedField();
+//                                               ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:71:48: Error: Can't use an expression of type 'void Function()?' as a function because it's potentially null.
+// Try calling using ?.call instead.
+//   nonNullableClass2.nullableFunctionTypedGetter();
+//                                                ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:74:50: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//   nonNullableClass2.nonNullableFunctionTypedField(0);
+//                                                  ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:75:51: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//   nonNullableClass2.nonNullableFunctionTypedGetter(0);
+//                                                   ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:78:18: Error: Method 'method' cannot be called on 'Class1?' because it is potentially null.
+//  - 'Class1' is from 'pkg/front_end/testcases/none/method_invocation.dart'.
+// Try calling using ?. instead.
+//   nullableClass1.method(0);
+//                  ^^^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:102:21: Error: The method 'unresolved' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/none/method_invocation.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'unresolved'.
+//   nonNullableClass1.unresolved();
+//                     ^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:105:27: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass1.method();
+//                           ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:106:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableFunctionType();
+//                          ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:132:19: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+//  - 'Function' is from 'dart:core'.
+// Try calling using ?.call instead.
+//   nullableFunction(0);
+//                   ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:133:20: Error: Method 'call' cannot be called on 'Function?' because it is potentially null.
+//  - 'Function' is from 'dart:core'.
+// Try calling using ?. instead.
+//   nullableFunction.call(0);
+//                    ^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:134:23: Error: Can't use an expression of type 'int Function(int)?' as a function because it's potentially null.
+// Try calling using ?.call instead.
+//   nullableFunctionType(0);
+//                       ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:135:24: Error: Method 'call' cannot be called on 'int Function(int)?' because it is potentially null.
+// Try calling using ?. instead.
+//   nullableFunctionType.call(0);
+//                        ^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:138:27: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass1.method().method(0);
+//                           ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → self::Class1
+    : super core::Object::•()
+    ;
+  method method(core::int o) → core::double
+    return 0.5;
+}
+class Class2<T extends core::Object? = dynamic> extends core::Object {
+  generic-covariant-impl field self::Class2::T% field;
+  field core::Function nonNullableFunctionField;
+  field core::Function? nullableFunctionField = null;
+  field () → void nonNullableFunctionTypedField;
+  field () →? void nullableFunctionTypedField = null;
+  constructor •(self::Class2::T% field, core::Function nonNullableFunctionField, () → void nonNullableFunctionTypedField) → self::Class2<self::Class2::T%>
+    : self::Class2::field = field, self::Class2::nonNullableFunctionField = nonNullableFunctionField, self::Class2::nonNullableFunctionTypedField = nonNullableFunctionTypedField, super core::Object::•()
+    ;
+  method call() → self::Class2::T%
+    return this.{self::Class2::field}{self::Class2::T%};
+  method method(core::int o) → self::Class2::T%
+    return this.{self::Class2::field}{self::Class2::T%};
+  get nonNullableFunctionGetter() → core::Function
+    return this.{self::Class2::nonNullableFunctionTypedField}{() → void};
+  get nullableFunctionGetter() → core::Function?
+    return this.{self::Class2::nonNullableFunctionTypedField}{() → void};
+  get nonNullableFunctionTypedGetter() → () → void
+    return this.{self::Class2::nonNullableFunctionTypedField}{() → void};
+  get nullableFunctionTypedGetter() → () →? void
+    return this.{self::Class2::nonNullableFunctionTypedField}{() → void};
+}
+static const field core::int i = #C1;
+static const field core::int j = #C2;
+static const field core::int k = #C3;
+static method test<T1 extends core::Function = core::Function, T2 extends (core::int) → core::int = (core::int) → core::int, T3 extends core::Object? = dynamic>(self::Class1 nonNullableClass1, self::Class1? nullableClass1, dynamic dyn, Never never, self::Class2<core::String> nonNullableClass2, self::Class2<core::String>? nullableClass2, core::Function nonNullableFunction, core::Function? nullableFunction, (core::int) → core::int nonNullableFunctionType, (core::int) →? core::int nullableFunctionType, <T extends core::Object? = dynamic>(T%) → T% genericFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2, self::test::T3% undeterminedTypeVariable) → dynamic {
+  core::print("InstanceInvocation");
+  nonNullableClass1.{self::Class1::method}(0){(core::int) → core::double};
+  let final self::Class1? #t1 = nullableClass1 in #t1 == null ?{core::double?} null : #t1{self::Class1}.{self::Class1::method}(0){(core::int) → core::double};
+  core::print("InstanceGet calls");
+  nonNullableClass2.{self::Class2::nonNullableFunctionField}{core::Function}();
+  nonNullableClass2.{self::Class2::nonNullableFunctionGetter}{core::Function}();
+  nonNullableClass2.{self::Class2::nonNullableFunctionTypedField}{() → void}(){() → void};
+  nonNullableClass2.{self::Class2::nonNullableFunctionTypedGetter}{() → void}(){() → void};
+  let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:68:42: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+ - 'Function' is from 'dart:core'.
+Try calling using ?.call instead.
+  nonNullableClass2.nullableFunctionField();
+                                         ^" in nonNullableClass2.{self::Class2::nullableFunctionField}{core::Function?}{<nullable>}.();
+  let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:69:43: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+ - 'Function' is from 'dart:core'.
+Try calling using ?.call instead.
+  nonNullableClass2.nullableFunctionGetter();
+                                          ^" in nonNullableClass2.{self::Class2::nullableFunctionGetter}{core::Function?}{<nullable>}.();
+  let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:70:47: Error: Can't use an expression of type 'void Function()?' as a function because it's potentially null.
+Try calling using ?.call instead.
+  nonNullableClass2.nullableFunctionTypedField();
+                                              ^" in nonNullableClass2.{self::Class2::nullableFunctionTypedField}{() →? void}{<nullable>}.(){() →? void};
+  let final<BottomType> #t5 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:71:48: Error: Can't use an expression of type 'void Function()?' as a function because it's potentially null.
+Try calling using ?.call instead.
+  nonNullableClass2.nullableFunctionTypedGetter();
+                                               ^" in nonNullableClass2.{self::Class2::nullableFunctionTypedGetter}{() →? void}{<nullable>}.(){() →? void};
+  let final self::Class2<core::String> #t6 = nonNullableClass2 in let final core::int #t7 = 0 in #t6.{self::Class2::nonNullableFunctionField}{core::Function}(#t7);
+  let final self::Class2<core::String> #t8 = nonNullableClass2 in let final core::int #t9 = 0 in #t8.{self::Class2::nonNullableFunctionGetter}{core::Function}(#t9);
+  let final self::Class2<core::String> #t10 = nonNullableClass2 in let final core::int #t11 = 0 in let final<BottomType> #t12 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:74:50: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+  nonNullableClass2.nonNullableFunctionTypedField(0);
+                                                 ^" in #t10.{self::Class2::nonNullableFunctionTypedField}{() → void}{<inapplicable>}.(#t11);
+  let final self::Class2<core::String> #t13 = nonNullableClass2 in let final core::int #t14 = 0 in let final<BottomType> #t15 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:75:51: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+  nonNullableClass2.nonNullableFunctionTypedGetter(0);
+                                                  ^" in #t13.{self::Class2::nonNullableFunctionTypedGetter}{() → void}{<inapplicable>}.(#t14);
+  core::print("InstanceInvocation (Nullable)");
+  let final<BottomType> #t16 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:78:18: Error: Method 'method' cannot be called on 'Class1?' because it is potentially null.
+ - 'Class1' is from 'pkg/front_end/testcases/none/method_invocation.dart'.
+Try calling using ?. instead.
+  nullableClass1.method(0);
+                 ^^^^^^" in nullableClass1.{self::Class1::method}{<nullable>}.(0){(core::int) → core::double};
+  core::print("DynamicInvocation");
+  dyn{dynamic}.method(0);
+  let final dynamic #t17 = dyn in #t17 == null ?{dynamic} null : #t17{dynamic}.method(0);
+  dyn{dynamic}.toString(0);
+  const core::int call_dyn = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:84:28: Error: Method invocation is not a constant expression.
+  const int call_dyn = dyn.toString(0);
+                           ^^^^^^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:84:28: Error: Method invocation is not a constant expression.
+  const int call_dyn = dyn.toString(0);
+                           ^^^^^^^^");
+  core::print("InstanceInvocation (Object)");
+  dyn.{core::Object::toString}(){() → core::String};
+  nullableClass1.{core::Object::toString}(){() → core::String};
+  nullableClass2.{core::Object::toString}(){() → core::String};
+  nullableFunction.{core::Object::toString}(){() → core::String};
+  nullableFunctionType.{core::Object::toString}(){() → core::String};
+  nullableTypeVariable1.{core::Object::toString}(){() → core::String};
+  nullableTypeVariable2.{core::Object::toString}(){() → core::String};
+  undeterminedTypeVariable.{core::Object::toString}(){() → core::String};
+  core::print("DynamicInvocation (Never)");
+  never{Never}.method(0);
+  never{Never}.toString();
+  core::print("DynamicInvocation (Unresolved)");
+  invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:102:21: Error: The method 'unresolved' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/none/method_invocation.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'unresolved'.
+  nonNullableClass1.unresolved();
+                    ^^^^^^^^^^";
+  core::print("DynamicInvocation (Inapplicable)");
+  let final<BottomType> #t18 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:105:27: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass1.method();
+                          ^" in nonNullableClass1.{self::Class1::method}{<inapplicable>}.(){() → invalid-type};
+  let final<BottomType> #t19 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:106:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableFunctionType();
+                         ^" in nonNullableFunctionType{<inapplicable>}.();
+  core::print("InstanceInvocation (generic)");
+  nonNullableClass2.{self::Class2::method}(0){(core::int) → core::String};
+  let final self::Class2<core::String>? #t20 = nullableClass2 in #t20 == null ?{core::String?} null : #t20{self::Class2<core::String>}.{self::Class2::method}(0){(core::int) → core::String};
+  nonNullableClass2.{self::Class2::call}(){() → core::String};
+  nonNullableClass2.{self::Class2::call}(){() → core::String};
+  core::print("FunctionInvocation");
+  nonNullableFunction(0);
+  nonNullableFunction(0);
+  let final core::Function? #t21 = nullableFunction in #t21 == null ?{dynamic} null : #t21{core::Function}(0);
+  nonNullableFunctionType(0){(core::int) → core::int};
+  nonNullableFunctionType(0){(core::int) → core::int};
+  let final (core::int) →? core::int #t22 = nullableFunctionType in #t22 == null ?{core::int?} null : #t22{(core::int) → core::int}(0){(core::int) → core::int};
+  genericFunctionType<core::int>(0){(core::int) → core::int};
+  genericFunctionType<core::num>(0){(core::num) → core::num};
+  core::num i = genericFunctionType<core::num>(0){(core::num) → core::num};
+  nonNullableTypeVariable1(0);
+  nonNullableTypeVariable1(0);
+  let final self::test::T1? #t23 = nullableTypeVariable1 in #t23 == null ?{dynamic} null : #t23{self::test::T1}(0);
+  nonNullableTypeVariable2(0){(core::int) → core::int};
+  nonNullableTypeVariable2(0){(core::int) → core::int};
+  let final self::test::T2? #t24 = nullableTypeVariable2 in #t24 == null ?{core::int?} null : #t24{self::test::T2}(0){(core::int) → core::int};
+  core::print("FunctionInvocation (Nullable)");
+  let final<BottomType> #t25 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:132:19: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+ - 'Function' is from 'dart:core'.
+Try calling using ?.call instead.
+  nullableFunction(0);
+                  ^" in nullableFunction{<nullable>}.(0);
+  let final<BottomType> #t26 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:133:20: Error: Method 'call' cannot be called on 'Function?' because it is potentially null.
+ - 'Function' is from 'dart:core'.
+Try calling using ?. instead.
+  nullableFunction.call(0);
+                   ^^^^" in nullableFunction{<nullable>}.(0);
+  let final<BottomType> #t27 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:134:23: Error: Can't use an expression of type 'int Function(int)?' as a function because it's potentially null.
+Try calling using ?.call instead.
+  nullableFunctionType(0);
+                      ^" in nullableFunctionType{<nullable>}.(0){(core::int) →? core::int};
+  let final<BottomType> #t28 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:135:24: Error: Method 'call' cannot be called on 'int Function(int)?' because it is potentially null.
+Try calling using ?. instead.
+  nullableFunctionType.call(0);
+                       ^^^^" in nullableFunctionType{<nullable>}.(0){(core::int) →? core::int};
+  core::print("DynamicInvocation (Invalid)");
+  (let final<BottomType> #t29 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:138:27: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass1.method().method(0);
+                          ^" in nonNullableClass1.{self::Class1::method}{<inapplicable>}.(){() → invalid-type}){dynamic}.method(0);
+  core::print("LocalFunctionInvocation");
+  function localFunction() → core::int
+    return 42;
+  function genericLocalFunction<T extends core::Object? = dynamic>(T% t) → T%
+    return t;
+  localFunction(){() → core::int};
+  genericLocalFunction<core::int>(0){(core::int) → core::int};
+  genericLocalFunction<core::num>(0){(core::num) → core::num};
+  const core::int call_localFunction = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:147:34: Error: Not a constant expression.
+  const int call_localFunction = localFunction();
+                                 ^^^^^^^^^^^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:147:34: Error: Not a constant expression.
+  const int call_localFunction = localFunction();
+                                 ^^^^^^^^^^^^^");
+  () → core::int f = () → core::int => 42;
+  const core::int call_f = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:152:22: Error: Not a constant expression.
+  const int call_f = f();
+                     ^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:152:22: Error: Not a constant expression.
+  const int call_f = f();
+                     ^");
+  core::print(#C4);
+  const core::bool equals = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:157:23: Error: Not a constant expression.
+  const bool equals = i == j;
+                      ^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:157:23: Error: Not a constant expression.
+  const bool equals = i == j;
+                      ^");
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 4
+  #C2 = 24
+  #C3 = 96
+  #C4 = false
+}
diff --git a/pkg/front_end/testcases/none/method_invocation.dart.textual_outline.expect b/pkg/front_end/testcases/none/method_invocation.dart.textual_outline.expect
new file mode 100644
index 0000000..b0ad48c
--- /dev/null
+++ b/pkg/front_end/testcases/none/method_invocation.dart.textual_outline.expect
@@ -0,0 +1,43 @@
+class Class1 {
+  double method(int o) => 0.5;
+}
+
+class Class2<T> {
+  T field;
+  Class2(this.field, this.nonNullableFunctionField,
+      this.nonNullableFunctionTypedField);
+  T call() => field;
+  T method(int o) => field;
+  Function nonNullableFunctionField;
+  Function get nonNullableFunctionGetter => nonNullableFunctionTypedField;
+  Function? nullableFunctionField;
+  Function? get nullableFunctionGetter => nonNullableFunctionTypedField;
+  void Function() nonNullableFunctionTypedField;
+  void Function() get nonNullableFunctionTypedGetter =>
+      nonNullableFunctionTypedField;
+  void Function()? nullableFunctionTypedField;
+  void Function()? get nullableFunctionTypedGetter =>
+      nonNullableFunctionTypedField;
+}
+
+const int i = 4;
+const int j = 24;
+const int k = i * j;
+test<T1 extends Function, T2 extends int Function(int), T3>(
+    Class1 nonNullableClass1,
+    Class1? nullableClass1,
+    dynamic dyn,
+    Never never,
+    Class2<String> nonNullableClass2,
+    Class2<String>? nullableClass2,
+    Function nonNullableFunction,
+    Function? nullableFunction,
+    int Function(int) nonNullableFunctionType,
+    int Function(int)? nullableFunctionType,
+    T Function<T>(T) genericFunctionType,
+    T1 nonNullableTypeVariable1,
+    T1? nullableTypeVariable1,
+    T2 nonNullableTypeVariable2,
+    T2? nullableTypeVariable2,
+    T3 undeterminedTypeVariable) {}
+main() {}
diff --git a/pkg/front_end/testcases/none/method_invocation.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/none/method_invocation.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..05863eb
--- /dev/null
+++ b/pkg/front_end/testcases/none/method_invocation.dart.textual_outline_modelled.expect
@@ -0,0 +1,43 @@
+class Class1 {
+  double method(int o) => 0.5;
+}
+
+class Class2<T> {
+  Class2(this.field, this.nonNullableFunctionField,
+      this.nonNullableFunctionTypedField);
+  Function? get nullableFunctionGetter => nonNullableFunctionTypedField;
+  Function? nullableFunctionField;
+  Function get nonNullableFunctionGetter => nonNullableFunctionTypedField;
+  Function nonNullableFunctionField;
+  T call() => field;
+  T field;
+  T method(int o) => field;
+  void Function()? get nullableFunctionTypedGetter =>
+      nonNullableFunctionTypedField;
+  void Function()? nullableFunctionTypedField;
+  void Function() get nonNullableFunctionTypedGetter =>
+      nonNullableFunctionTypedField;
+  void Function() nonNullableFunctionTypedField;
+}
+
+const int i = 4;
+const int j = 24;
+const int k = i * j;
+main() {}
+test<T1 extends Function, T2 extends int Function(int), T3>(
+    Class1 nonNullableClass1,
+    Class1? nullableClass1,
+    dynamic dyn,
+    Never never,
+    Class2<String> nonNullableClass2,
+    Class2<String>? nullableClass2,
+    Function nonNullableFunction,
+    Function? nullableFunction,
+    int Function(int) nonNullableFunctionType,
+    int Function(int)? nullableFunctionType,
+    T Function<T>(T) genericFunctionType,
+    T1 nonNullableTypeVariable1,
+    T1? nullableTypeVariable1,
+    T2 nonNullableTypeVariable2,
+    T2? nullableTypeVariable2,
+    T3 undeterminedTypeVariable) {}
diff --git a/pkg/front_end/testcases/none/method_invocation.dart.weak.expect b/pkg/front_end/testcases/none/method_invocation.dart.weak.expect
new file mode 100644
index 0000000..0e8d2d1e8
--- /dev/null
+++ b/pkg/front_end/testcases/none/method_invocation.dart.weak.expect
@@ -0,0 +1,297 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/method_invocation.dart:84:24: Error: Not a constant expression.
+//   const int call_dyn = dyn.toString(0);
+//                        ^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:84:28: Error: Method invocation is not a constant expression.
+//   const int call_dyn = dyn.toString(0);
+//                            ^^^^^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:147:34: Error: Not a constant expression.
+//   const int call_localFunction = localFunction();
+//                                  ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:152:22: Error: Not a constant expression.
+//   const int call_f = f();
+//                      ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:157:23: Error: Not a constant expression.
+//   const bool equals = i == j;
+//                       ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:68:42: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+//  - 'Function' is from 'dart:core'.
+// Try calling using ?.call instead.
+//   nonNullableClass2.nullableFunctionField();
+//                                          ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:69:43: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+//  - 'Function' is from 'dart:core'.
+// Try calling using ?.call instead.
+//   nonNullableClass2.nullableFunctionGetter();
+//                                           ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:70:47: Error: Can't use an expression of type 'void Function()?' as a function because it's potentially null.
+// Try calling using ?.call instead.
+//   nonNullableClass2.nullableFunctionTypedField();
+//                                               ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:71:48: Error: Can't use an expression of type 'void Function()?' as a function because it's potentially null.
+// Try calling using ?.call instead.
+//   nonNullableClass2.nullableFunctionTypedGetter();
+//                                                ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:74:50: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//   nonNullableClass2.nonNullableFunctionTypedField(0);
+//                                                  ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:75:51: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//   nonNullableClass2.nonNullableFunctionTypedGetter(0);
+//                                                   ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:78:18: Error: Method 'method' cannot be called on 'Class1?' because it is potentially null.
+//  - 'Class1' is from 'pkg/front_end/testcases/none/method_invocation.dart'.
+// Try calling using ?. instead.
+//   nullableClass1.method(0);
+//                  ^^^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:102:21: Error: The method 'unresolved' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/none/method_invocation.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'unresolved'.
+//   nonNullableClass1.unresolved();
+//                     ^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:105:27: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass1.method();
+//                           ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:106:26: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableFunctionType();
+//                          ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:132:19: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+//  - 'Function' is from 'dart:core'.
+// Try calling using ?.call instead.
+//   nullableFunction(0);
+//                   ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:133:20: Error: Method 'call' cannot be called on 'Function?' because it is potentially null.
+//  - 'Function' is from 'dart:core'.
+// Try calling using ?. instead.
+//   nullableFunction.call(0);
+//                    ^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:134:23: Error: Can't use an expression of type 'int Function(int)?' as a function because it's potentially null.
+// Try calling using ?.call instead.
+//   nullableFunctionType(0);
+//                       ^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:135:24: Error: Method 'call' cannot be called on 'int Function(int)?' because it is potentially null.
+// Try calling using ?. instead.
+//   nullableFunctionType.call(0);
+//                        ^^^^
+//
+// pkg/front_end/testcases/none/method_invocation.dart:138:27: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass1.method().method(0);
+//                           ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → self::Class1
+    : super core::Object::•()
+    ;
+  method method(core::int o) → core::double
+    return 0.5;
+}
+class Class2<T extends core::Object? = dynamic> extends core::Object {
+  generic-covariant-impl field self::Class2::T% field;
+  field core::Function nonNullableFunctionField;
+  field core::Function? nullableFunctionField = null;
+  field () → void nonNullableFunctionTypedField;
+  field () →? void nullableFunctionTypedField = null;
+  constructor •(self::Class2::T% field, core::Function nonNullableFunctionField, () → void nonNullableFunctionTypedField) → self::Class2<self::Class2::T%>
+    : self::Class2::field = field, self::Class2::nonNullableFunctionField = nonNullableFunctionField, self::Class2::nonNullableFunctionTypedField = nonNullableFunctionTypedField, super core::Object::•()
+    ;
+  method call() → self::Class2::T%
+    return this.{self::Class2::field}{self::Class2::T%};
+  method method(core::int o) → self::Class2::T%
+    return this.{self::Class2::field}{self::Class2::T%};
+  get nonNullableFunctionGetter() → core::Function
+    return this.{self::Class2::nonNullableFunctionTypedField}{() → void};
+  get nullableFunctionGetter() → core::Function?
+    return this.{self::Class2::nonNullableFunctionTypedField}{() → void};
+  get nonNullableFunctionTypedGetter() → () → void
+    return this.{self::Class2::nonNullableFunctionTypedField}{() → void};
+  get nullableFunctionTypedGetter() → () →? void
+    return this.{self::Class2::nonNullableFunctionTypedField}{() → void};
+}
+static const field core::int i = #C1;
+static const field core::int j = #C2;
+static const field core::int k = #C3;
+static method test<T1 extends core::Function = core::Function, T2 extends (core::int) → core::int = (core::int) → core::int, T3 extends core::Object? = dynamic>(self::Class1 nonNullableClass1, self::Class1? nullableClass1, dynamic dyn, Never never, self::Class2<core::String> nonNullableClass2, self::Class2<core::String>? nullableClass2, core::Function nonNullableFunction, core::Function? nullableFunction, (core::int) → core::int nonNullableFunctionType, (core::int) →? core::int nullableFunctionType, <T extends core::Object? = dynamic>(T%) → T% genericFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2, self::test::T3% undeterminedTypeVariable) → dynamic {
+  core::print("InstanceInvocation");
+  nonNullableClass1.{self::Class1::method}(0){(core::int) → core::double};
+  let final self::Class1? #t1 = nullableClass1 in #t1 == null ?{core::double?} null : #t1{self::Class1}.{self::Class1::method}(0){(core::int) → core::double};
+  core::print("InstanceGet calls");
+  nonNullableClass2.{self::Class2::nonNullableFunctionField}{core::Function}();
+  nonNullableClass2.{self::Class2::nonNullableFunctionGetter}{core::Function}();
+  nonNullableClass2.{self::Class2::nonNullableFunctionTypedField}{() → void}(){() → void};
+  nonNullableClass2.{self::Class2::nonNullableFunctionTypedGetter}{() → void}(){() → void};
+  let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:68:42: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+ - 'Function' is from 'dart:core'.
+Try calling using ?.call instead.
+  nonNullableClass2.nullableFunctionField();
+                                         ^" in nonNullableClass2.{self::Class2::nullableFunctionField}{core::Function?}{<nullable>}.();
+  let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:69:43: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+ - 'Function' is from 'dart:core'.
+Try calling using ?.call instead.
+  nonNullableClass2.nullableFunctionGetter();
+                                          ^" in nonNullableClass2.{self::Class2::nullableFunctionGetter}{core::Function?}{<nullable>}.();
+  let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:70:47: Error: Can't use an expression of type 'void Function()?' as a function because it's potentially null.
+Try calling using ?.call instead.
+  nonNullableClass2.nullableFunctionTypedField();
+                                              ^" in nonNullableClass2.{self::Class2::nullableFunctionTypedField}{() →? void}{<nullable>}.(){() →? void};
+  let final<BottomType> #t5 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:71:48: Error: Can't use an expression of type 'void Function()?' as a function because it's potentially null.
+Try calling using ?.call instead.
+  nonNullableClass2.nullableFunctionTypedGetter();
+                                               ^" in nonNullableClass2.{self::Class2::nullableFunctionTypedGetter}{() →? void}{<nullable>}.(){() →? void};
+  let final self::Class2<core::String> #t6 = nonNullableClass2 in let final core::int #t7 = 0 in #t6.{self::Class2::nonNullableFunctionField}{core::Function}(#t7);
+  let final self::Class2<core::String> #t8 = nonNullableClass2 in let final core::int #t9 = 0 in #t8.{self::Class2::nonNullableFunctionGetter}{core::Function}(#t9);
+  let final self::Class2<core::String> #t10 = nonNullableClass2 in let final core::int #t11 = 0 in let final<BottomType> #t12 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:74:50: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+  nonNullableClass2.nonNullableFunctionTypedField(0);
+                                                 ^" in #t10.{self::Class2::nonNullableFunctionTypedField}{() → void}{<inapplicable>}.(#t11);
+  let final self::Class2<core::String> #t13 = nonNullableClass2 in let final core::int #t14 = 0 in let final<BottomType> #t15 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:75:51: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+  nonNullableClass2.nonNullableFunctionTypedGetter(0);
+                                                  ^" in #t13.{self::Class2::nonNullableFunctionTypedGetter}{() → void}{<inapplicable>}.(#t14);
+  core::print("InstanceInvocation (Nullable)");
+  let final<BottomType> #t16 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:78:18: Error: Method 'method' cannot be called on 'Class1?' because it is potentially null.
+ - 'Class1' is from 'pkg/front_end/testcases/none/method_invocation.dart'.
+Try calling using ?. instead.
+  nullableClass1.method(0);
+                 ^^^^^^" in nullableClass1.{self::Class1::method}{<nullable>}.(0){(core::int) → core::double};
+  core::print("DynamicInvocation");
+  dyn{dynamic}.method(0);
+  let final dynamic #t17 = dyn in #t17 == null ?{dynamic} null : #t17{dynamic}.method(0);
+  dyn{dynamic}.toString(0);
+  const core::int call_dyn = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:84:28: Error: Method invocation is not a constant expression.
+  const int call_dyn = dyn.toString(0);
+                           ^^^^^^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:84:28: Error: Method invocation is not a constant expression.
+  const int call_dyn = dyn.toString(0);
+                           ^^^^^^^^");
+  core::print("InstanceInvocation (Object)");
+  dyn.{core::Object::toString}(){() → core::String};
+  nullableClass1.{core::Object::toString}(){() → core::String};
+  nullableClass2.{core::Object::toString}(){() → core::String};
+  nullableFunction.{core::Object::toString}(){() → core::String};
+  nullableFunctionType.{core::Object::toString}(){() → core::String};
+  nullableTypeVariable1.{core::Object::toString}(){() → core::String};
+  nullableTypeVariable2.{core::Object::toString}(){() → core::String};
+  undeterminedTypeVariable.{core::Object::toString}(){() → core::String};
+  core::print("DynamicInvocation (Never)");
+  let final Never #t18 = (let final Never #t19 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")){Never}.method(0) in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  let final Never #t20 = (let final Never #t21 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")){Never}.toString() in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  core::print("DynamicInvocation (Unresolved)");
+  invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:102:21: Error: The method 'unresolved' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/none/method_invocation.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'unresolved'.
+  nonNullableClass1.unresolved();
+                    ^^^^^^^^^^";
+  core::print("DynamicInvocation (Inapplicable)");
+  let final<BottomType> #t22 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:105:27: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass1.method();
+                          ^" in nonNullableClass1.{self::Class1::method}{<inapplicable>}.(){() → invalid-type};
+  let final<BottomType> #t23 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:106:26: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableFunctionType();
+                         ^" in nonNullableFunctionType{<inapplicable>}.();
+  core::print("InstanceInvocation (generic)");
+  nonNullableClass2.{self::Class2::method}(0){(core::int) → core::String};
+  let final self::Class2<core::String>? #t24 = nullableClass2 in #t24 == null ?{core::String?} null : #t24{self::Class2<core::String>}.{self::Class2::method}(0){(core::int) → core::String};
+  nonNullableClass2.{self::Class2::call}(){() → core::String};
+  nonNullableClass2.{self::Class2::call}(){() → core::String};
+  core::print("FunctionInvocation");
+  nonNullableFunction(0);
+  nonNullableFunction(0);
+  let final core::Function? #t25 = nullableFunction in #t25 == null ?{dynamic} null : #t25{core::Function}(0);
+  nonNullableFunctionType(0){(core::int) → core::int};
+  nonNullableFunctionType(0){(core::int) → core::int};
+  let final (core::int) →? core::int #t26 = nullableFunctionType in #t26 == null ?{core::int?} null : #t26{(core::int) → core::int}(0){(core::int) → core::int};
+  genericFunctionType<core::int>(0){(core::int) → core::int};
+  genericFunctionType<core::num>(0){(core::num) → core::num};
+  core::num i = genericFunctionType<core::num>(0){(core::num) → core::num};
+  nonNullableTypeVariable1(0);
+  nonNullableTypeVariable1(0);
+  let final self::test::T1? #t27 = nullableTypeVariable1 in #t27 == null ?{dynamic} null : #t27{self::test::T1}(0);
+  nonNullableTypeVariable2(0){(core::int) → core::int};
+  nonNullableTypeVariable2(0){(core::int) → core::int};
+  let final self::test::T2? #t28 = nullableTypeVariable2 in #t28 == null ?{core::int?} null : #t28{self::test::T2}(0){(core::int) → core::int};
+  core::print("FunctionInvocation (Nullable)");
+  let final<BottomType> #t29 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:132:19: Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
+ - 'Function' is from 'dart:core'.
+Try calling using ?.call instead.
+  nullableFunction(0);
+                  ^" in nullableFunction{<nullable>}.(0);
+  let final<BottomType> #t30 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:133:20: Error: Method 'call' cannot be called on 'Function?' because it is potentially null.
+ - 'Function' is from 'dart:core'.
+Try calling using ?. instead.
+  nullableFunction.call(0);
+                   ^^^^" in nullableFunction{<nullable>}.(0);
+  let final<BottomType> #t31 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:134:23: Error: Can't use an expression of type 'int Function(int)?' as a function because it's potentially null.
+Try calling using ?.call instead.
+  nullableFunctionType(0);
+                      ^" in nullableFunctionType{<nullable>}.(0){(core::int) →? core::int};
+  let final<BottomType> #t32 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:135:24: Error: Method 'call' cannot be called on 'int Function(int)?' because it is potentially null.
+Try calling using ?. instead.
+  nullableFunctionType.call(0);
+                       ^^^^" in nullableFunctionType{<nullable>}.(0){(core::int) →? core::int};
+  core::print("DynamicInvocation (Invalid)");
+  (let final<BottomType> #t33 = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:138:27: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass1.method().method(0);
+                          ^" in nonNullableClass1.{self::Class1::method}{<inapplicable>}.(){() → invalid-type}){dynamic}.method(0);
+  core::print("LocalFunctionInvocation");
+  function localFunction() → core::int
+    return 42;
+  function genericLocalFunction<T extends core::Object? = dynamic>(T% t) → T%
+    return t;
+  localFunction(){() → core::int};
+  genericLocalFunction<core::int>(0){(core::int) → core::int};
+  genericLocalFunction<core::num>(0){(core::num) → core::num};
+  const core::int call_localFunction = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:147:34: Error: Not a constant expression.
+  const int call_localFunction = localFunction();
+                                 ^^^^^^^^^^^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:147:34: Error: Not a constant expression.
+  const int call_localFunction = localFunction();
+                                 ^^^^^^^^^^^^^");
+  () → core::int f = () → core::int => 42;
+  const core::int call_f = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:152:22: Error: Not a constant expression.
+  const int call_f = f();
+                     ^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:152:22: Error: Not a constant expression.
+  const int call_f = f();
+                     ^");
+  core::print(#C4);
+  const core::bool equals = invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:157:23: Error: Not a constant expression.
+  const bool equals = i == j;
+                      ^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/method_invocation.dart:157:23: Error: Not a constant expression.
+  const bool equals = i == j;
+                      ^");
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 4
+  #C2 = 24
+  #C3 = 96
+  #C4 = false
+}
diff --git a/pkg/front_end/testcases/none/mixin_covariant.dart.strong.expect b/pkg/front_end/testcases/none/mixin_covariant.dart.strong.expect
index 412bbf0..028d0ab 100644
--- a/pkg/front_end/testcases/none/mixin_covariant.dart.strong.expect
+++ b/pkg/front_end/testcases/none/mixin_covariant.dart.strong.expect
@@ -45,29 +45,29 @@
 }
 static method main() → dynamic {
   self::Class c = new self::Class::•();
-  self::expect("Mixin", c.{self::Mixin::method1}(0, 1));
-  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method2}(0, 1));
-  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method3}(0, 1));
-  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method4}(0, 1));
+  self::expect("Mixin", c.{self::Mixin::method1}(0, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method2}(0, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method3}(0, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method4}(0, 1){(core::num, core::num) → core::String});
   self::Superclass s = c;
-  self::expect("Mixin", s.{self::Superclass::method1}(0.5, 1.5));
-  self::throws(() → void => s.{self::Superclass::method2}(0.5, 1.5));
-  self::expect("Mixin", s.{self::Superclass::method3}(0.5, 1));
-  self::throws(() → void => s.{self::Superclass::method4}(0.5, 1));
-  self::expect("Mixin", s.{self::Superclass::method4}(1, 0.5));
+  self::expect("Mixin", s.{self::Superclass::method1}(0.5, 1.5){(core::num, core::num) → core::String});
+  self::throws(() → void => s.{self::Superclass::method2}(0.5, 1.5){(core::num, core::num) → core::String});
+  self::expect("Mixin", s.{self::Superclass::method3}(0.5, 1){(core::num, core::int) → core::String});
+  self::throws(() → void => s.{self::Superclass::method4}(0.5, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", s.{self::Superclass::method4}(1, 0.5){(core::num, core::num) → core::String});
   self::Mixin m = c;
-  self::expect("Mixin", m.{self::Mixin::method1}(0, 1));
-  self::expect("Mixin", m.{self::Mixin::method2}(0, 1));
-  self::expect("Mixin", m.{self::Mixin::method3}(0, 1));
-  self::expect("Mixin", m.{self::Mixin::method4}(0, 1));
+  self::expect("Mixin", m.{self::Mixin::method1}(0, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", m.{self::Mixin::method2}(0, 1){(core::int, core::num) → core::String});
+  self::expect("Mixin", m.{self::Mixin::method3}(0, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", m.{self::Mixin::method4}(0, 1){(core::int, core::int) → core::String});
 }
 static method expect(dynamic expected, dynamic actual) → void {
-  if(!expected.{core::Object::==}(actual))
+  if(expected !={core::Object::==}{(core::Object) → core::bool} actual)
     throw "Expected ${expected}, actual ${actual}";
 }
 static method throws(() → void f) → void {
   try {
-    f.call();
+    f(){() → void};
   }
   on core::Object catch(final core::Object _) {
     return;
diff --git a/pkg/front_end/testcases/none/mixin_covariant.dart.weak.expect b/pkg/front_end/testcases/none/mixin_covariant.dart.weak.expect
index 412bbf0..028d0ab 100644
--- a/pkg/front_end/testcases/none/mixin_covariant.dart.weak.expect
+++ b/pkg/front_end/testcases/none/mixin_covariant.dart.weak.expect
@@ -45,29 +45,29 @@
 }
 static method main() → dynamic {
   self::Class c = new self::Class::•();
-  self::expect("Mixin", c.{self::Mixin::method1}(0, 1));
-  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method2}(0, 1));
-  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method3}(0, 1));
-  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method4}(0, 1));
+  self::expect("Mixin", c.{self::Mixin::method1}(0, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method2}(0, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method3}(0, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", c.{self::_Class&Superclass&Mixin::method4}(0, 1){(core::num, core::num) → core::String});
   self::Superclass s = c;
-  self::expect("Mixin", s.{self::Superclass::method1}(0.5, 1.5));
-  self::throws(() → void => s.{self::Superclass::method2}(0.5, 1.5));
-  self::expect("Mixin", s.{self::Superclass::method3}(0.5, 1));
-  self::throws(() → void => s.{self::Superclass::method4}(0.5, 1));
-  self::expect("Mixin", s.{self::Superclass::method4}(1, 0.5));
+  self::expect("Mixin", s.{self::Superclass::method1}(0.5, 1.5){(core::num, core::num) → core::String});
+  self::throws(() → void => s.{self::Superclass::method2}(0.5, 1.5){(core::num, core::num) → core::String});
+  self::expect("Mixin", s.{self::Superclass::method3}(0.5, 1){(core::num, core::int) → core::String});
+  self::throws(() → void => s.{self::Superclass::method4}(0.5, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", s.{self::Superclass::method4}(1, 0.5){(core::num, core::num) → core::String});
   self::Mixin m = c;
-  self::expect("Mixin", m.{self::Mixin::method1}(0, 1));
-  self::expect("Mixin", m.{self::Mixin::method2}(0, 1));
-  self::expect("Mixin", m.{self::Mixin::method3}(0, 1));
-  self::expect("Mixin", m.{self::Mixin::method4}(0, 1));
+  self::expect("Mixin", m.{self::Mixin::method1}(0, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", m.{self::Mixin::method2}(0, 1){(core::int, core::num) → core::String});
+  self::expect("Mixin", m.{self::Mixin::method3}(0, 1){(core::num, core::num) → core::String});
+  self::expect("Mixin", m.{self::Mixin::method4}(0, 1){(core::int, core::int) → core::String});
 }
 static method expect(dynamic expected, dynamic actual) → void {
-  if(!expected.{core::Object::==}(actual))
+  if(expected !={core::Object::==}{(core::Object) → core::bool} actual)
     throw "Expected ${expected}, actual ${actual}";
 }
 static method throws(() → void f) → void {
   try {
-    f.call();
+    f(){() → void};
   }
   on core::Object catch(final core::Object _) {
     return;
diff --git a/pkg/front_end/testcases/none/operator.dart b/pkg/front_end/testcases/none/operator.dart
new file mode 100644
index 0000000..624663e
--- /dev/null
+++ b/pkg/front_end/testcases/none/operator.dart
@@ -0,0 +1,132 @@
+// 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.md file.
+
+class Class<T> {
+  Class<T> operator +(Class<T> other) => other;
+
+  Class<T> operator -() => this;
+
+  Class<T> operator [](int index) => this;
+
+  operator []=(int index, Class<T> value) {}
+
+  int method(double o) => 42;
+}
+
+add(num n, int i, double d, Class<String> c, dynamic dyn, Never never,
+    String string) {
+  print('InstanceInvocation');
+  n + n;
+  n + i;
+  n + d;
+  n + dyn;
+
+  print('InstanceInvocation');
+  i + n;
+  i + i;
+  i + d;
+  i + dyn;
+
+  print('InstanceInvocation');
+  d + n;
+  d + i;
+  d + d;
+  i + dyn;
+
+  print('InstanceInvocation');
+  c + c;
+  c + dyn;
+
+  print('DynamicInvocation');
+  dyn + n;
+
+  print('DynamicInvocation (Never)');
+  never + n;
+
+  print('DynamicInvocation (Invalid)');
+  string - 42;
+}
+
+unaryMinus(num n, int i, double d, Class<String> c, dynamic dyn, Never never,
+    String string) {
+  print('InstanceInvocation');
+  -n;
+  -i;
+  -d;
+  -c;
+
+  print('DynamicInvocation');
+  -dyn;
+
+  print('DynamicInvocation (Never)');
+  -never;
+
+  print('DynamicInvocation (Invalid)');
+  -c.method();
+
+  print('DynamicInvocation (Unresolved)');
+  -string;
+}
+
+indexGet(List<int> list, Map<String, double> map, Class<String> c, dynamic dyn,
+    Never never, String string) {
+  print('InstanceInvocation');
+  list[0];
+  map['foo'];
+  c[0];
+
+  print('DynamicInvocation');
+  dyn[0];
+
+  print('DynamicInvocation (Never)');
+  never[0];
+
+  print('DynamicInvocation (Invalid)');
+  c.method()[0];
+
+  print('DynamicInvocation (Unresolved)');
+  string[0];
+}
+
+indexSet(List<int> list, Map<String, double> map, Class<String> c, dynamic dyn,
+    Never never) {
+  print('InstanceInvocation');
+  list[0] = 42;
+  map['foo'] = 0.5;
+  c[0] = c;
+
+  print('DynamicInvocation');
+  dyn[0] = 42;
+
+  print('DynamicInvocation (Never)');
+  never[0] = 42;
+
+  print('DynamicInvocation (Invalid)');
+  c.method()[0] = 42;
+
+  print('DynamicInvocation (Unresolved)');
+  string[0] = 42;
+}
+
+compound(List<int> list, Map<String, double> map, Class<String> c, dynamic dyn,
+    Never never) {
+  print('InstanceInvocation');
+  list[0] += 42;
+  map['foo'] += 0.5;
+  c[0] += c;
+
+  print('DynamicInvocation');
+  dyn[0] += 42;
+
+  print('DynamicInvocation (Never)');
+  never[0] += 42;
+
+  print('DynamicInvocation (Invalid)');
+  c.method()[0] += 42;
+
+  print('DynamicInvocation (Unresolved)');
+  string[0] += 42;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/none/operator.dart.outline.expect b/pkg/front_end/testcases/none/operator.dart.outline.expect
new file mode 100644
index 0000000..b105389
--- /dev/null
+++ b/pkg/front_end/testcases/none/operator.dart.outline.expect
@@ -0,0 +1,30 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T%>
+    ;
+  operator +(generic-covariant-impl self::Class<self::Class::T%> other) → self::Class<self::Class::T%>
+    ;
+  operator unary-() → self::Class<self::Class::T%>
+    ;
+  operator [](core::int index) → self::Class<self::Class::T%>
+    ;
+  operator []=(core::int index, generic-covariant-impl self::Class<self::Class::T%> value) → void
+    ;
+  method method(core::double o) → core::int
+    ;
+}
+static method add(core::num n, core::int i, core::double d, self::Class<core::String> c, dynamic dyn, Never never, core::String string) → dynamic
+  ;
+static method unaryMinus(core::num n, core::int i, core::double d, self::Class<core::String> c, dynamic dyn, Never never, core::String string) → dynamic
+  ;
+static method indexGet(core::List<core::int> list, core::Map<core::String, core::double> map, self::Class<core::String> c, dynamic dyn, Never never, core::String string) → dynamic
+  ;
+static method indexSet(core::List<core::int> list, core::Map<core::String, core::double> map, self::Class<core::String> c, dynamic dyn, Never never) → dynamic
+  ;
+static method compound(core::List<core::int> list, core::Map<core::String, core::double> map, self::Class<core::String> c, dynamic dyn, Never never) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/none/operator.dart.strong.expect b/pkg/front_end/testcases/none/operator.dart.strong.expect
new file mode 100644
index 0000000..c78387c
--- /dev/null
+++ b/pkg/front_end/testcases/none/operator.dart.strong.expect
@@ -0,0 +1,163 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/operator.dart:48:10: Error: The operator '-' isn't defined for the class 'String'.
+// Try correcting the operator to an existing operator, or defining a '-' operator.
+//   string - 42;
+//          ^
+//
+// pkg/front_end/testcases/none/operator.dart:66:12: Error: Too few positional arguments: 1 required, 0 given.
+//   -c.method();
+//            ^
+//
+// pkg/front_end/testcases/none/operator.dart:69:3: Error: The operator 'unary-' isn't defined for the class 'String'.
+// Try correcting the operator to an existing operator, or defining a 'unary-' operator.
+//   -string;
+//   ^
+//
+// pkg/front_end/testcases/none/operator.dart:86:11: Error: Too few positional arguments: 1 required, 0 given.
+//   c.method()[0];
+//           ^
+//
+// pkg/front_end/testcases/none/operator.dart:109:3: Error: Getter not found: 'string'.
+//   string[0] = 42;
+//   ^^^^^^
+//
+// pkg/front_end/testcases/none/operator.dart:106:11: Error: Too few positional arguments: 1 required, 0 given.
+//   c.method()[0] = 42;
+//           ^
+//
+// pkg/front_end/testcases/none/operator.dart:129:3: Error: Getter not found: 'string'.
+//   string[0] += 42;
+//   ^^^^^^
+//
+// pkg/front_end/testcases/none/operator.dart:116:14: Error: Operator '+' cannot be called on 'double?' because it is potentially null.
+//   map['foo'] += 0.5;
+//              ^
+//
+// pkg/front_end/testcases/none/operator.dart:126:11: Error: Too few positional arguments: 1 required, 0 given.
+//   c.method()[0] += 42;
+//           ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T%>
+    : super core::Object::•()
+    ;
+  operator +(generic-covariant-impl self::Class<self::Class::T%> other) → self::Class<self::Class::T%>
+    return other;
+  operator unary-() → self::Class<self::Class::T%>
+    return this;
+  operator [](core::int index) → self::Class<self::Class::T%>
+    return this;
+  operator []=(core::int index, generic-covariant-impl self::Class<self::Class::T%> value) → void {}
+  method method(core::double o) → core::int
+    return 42;
+}
+static method add(core::num n, core::int i, core::double d, self::Class<core::String> c, dynamic dyn, Never never, core::String string) → dynamic {
+  core::print("InstanceInvocation");
+  n.{core::num::+}(n){(core::num) → core::num};
+  n.{core::num::+}(i){(core::num) → core::num};
+  n.{core::num::+}(d){(core::num) → core::double};
+  n.{core::num::+}(dyn as{TypeError,ForDynamic,ForNonNullableByDefault} core::num){(core::num) → core::num};
+  core::print("InstanceInvocation");
+  i.{core::num::+}(n){(core::num) → core::num};
+  i.{core::num::+}(i){(core::num) → core::int};
+  i.{core::num::+}(d){(core::num) → core::double};
+  i.{core::num::+}(dyn as{TypeError,ForDynamic,ForNonNullableByDefault} core::num){(core::num) → core::num};
+  core::print("InstanceInvocation");
+  d.{core::double::+}(n){(core::num) → core::double};
+  d.{core::double::+}(i){(core::num) → core::double};
+  d.{core::double::+}(d){(core::num) → core::double};
+  i.{core::num::+}(dyn as{TypeError,ForDynamic,ForNonNullableByDefault} core::num){(core::num) → core::num};
+  core::print("InstanceInvocation");
+  c.{self::Class::+}(c){(self::Class<core::String>) → self::Class<core::String>};
+  c.{self::Class::+}(dyn as{TypeError,ForDynamic,ForNonNullableByDefault} self::Class<core::String>){(self::Class<core::String>) → self::Class<core::String>};
+  core::print("DynamicInvocation");
+  dyn{dynamic}.+(n);
+  core::print("DynamicInvocation (Never)");
+  never{Never}.+(n);
+  core::print("DynamicInvocation (Invalid)");
+  invalid-expression "pkg/front_end/testcases/none/operator.dart:48:10: Error: The operator '-' isn't defined for the class 'String'.
+Try correcting the operator to an existing operator, or defining a '-' operator.
+  string - 42;
+         ^";
+}
+static method unaryMinus(core::num n, core::int i, core::double d, self::Class<core::String> c, dynamic dyn, Never never, core::String string) → dynamic {
+  core::print("InstanceInvocation");
+  n.{core::num::unary-}(){() → core::num};
+  i.{core::int::unary-}(){() → core::int};
+  d.{core::double::unary-}(){() → core::double};
+  c.{self::Class::unary-}(){() → self::Class<core::String>};
+  core::print("DynamicInvocation");
+  dyn{dynamic}.unary-();
+  core::print("DynamicInvocation (Never)");
+  never{Never}.unary-();
+  core::print("DynamicInvocation (Invalid)");
+  (let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/none/operator.dart:66:12: Error: Too few positional arguments: 1 required, 0 given.
+  -c.method();
+           ^" in c.{self::Class::method}{<inapplicable>}.(){() → invalid-type}){<invalid>}.unary-();
+  core::print("DynamicInvocation (Unresolved)");
+  invalid-expression "pkg/front_end/testcases/none/operator.dart:69:3: Error: The operator 'unary-' isn't defined for the class 'String'.
+Try correcting the operator to an existing operator, or defining a 'unary-' operator.
+  -string;
+  ^";
+}
+static method indexGet(core::List<core::int> list, core::Map<core::String, core::double> map, self::Class<core::String> c, dynamic dyn, Never never, core::String string) → dynamic {
+  core::print("InstanceInvocation");
+  list.{core::List::[]}(0){(core::int) → core::int};
+  map.{core::Map::[]}("foo"){(core::Object?) → core::double?};
+  c.{self::Class::[]}(0){(core::int) → self::Class<core::String>};
+  core::print("DynamicInvocation");
+  dyn{dynamic}.[](0);
+  core::print("DynamicInvocation (Never)");
+  never{Never}.[](0);
+  core::print("DynamicInvocation (Invalid)");
+  (let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/none/operator.dart:86:11: Error: Too few positional arguments: 1 required, 0 given.
+  c.method()[0];
+          ^" in c.{self::Class::method}{<inapplicable>}.(){() → invalid-type}){<invalid>}.[](0);
+  core::print("DynamicInvocation (Unresolved)");
+  string.{core::String::[]}(0){(core::int) → core::String};
+}
+static method indexSet(core::List<core::int> list, core::Map<core::String, core::double> map, self::Class<core::String> c, dynamic dyn, Never never) → dynamic {
+  core::print("InstanceInvocation");
+  list.{core::List::[]=}(0, 42){(core::int, core::int) → void};
+  map.{core::Map::[]=}("foo", 0.5){(core::String, core::double) → void};
+  c.{self::Class::[]=}(0, c){(core::int, self::Class<core::String>) → void};
+  core::print("DynamicInvocation");
+  dyn{dynamic}.[]=(0, 42);
+  core::print("DynamicInvocation (Never)");
+  never{Never}.[]=(0, 42);
+  core::print("DynamicInvocation (Invalid)");
+  (let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/none/operator.dart:106:11: Error: Too few positional arguments: 1 required, 0 given.
+  c.method()[0] = 42;
+          ^" in c.{self::Class::method}{<inapplicable>}.(){() → invalid-type}){<invalid>}.[]=(0, 42);
+  core::print("DynamicInvocation (Unresolved)");
+  invalid-expression "pkg/front_end/testcases/none/operator.dart:109:3: Error: Getter not found: 'string'.
+  string[0] = 42;
+  ^^^^^^"{dynamic}.[]=(0, 42);
+}
+static method compound(core::List<core::int> list, core::Map<core::String, core::double> map, self::Class<core::String> c, dynamic dyn, Never never) → dynamic {
+  core::print("InstanceInvocation");
+  let final core::List<core::int> #t4 = list in let final core::int #t5 = 0 in #t4.{core::List::[]=}(#t5, #t4.{core::List::[]}(#t5){(core::int) → core::int}.{core::num::+}(42){(core::num) → core::int}){(core::int, core::int) → void};
+  let final core::Map<core::String, core::double> #t6 = map in let final core::String #t7 = "foo" in #t6.{core::Map::[]=}(#t7, let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/none/operator.dart:116:14: Error: Operator '+' cannot be called on 'double?' because it is potentially null.
+  map['foo'] += 0.5;
+             ^" in #t6.{core::Map::[]}(#t7){(core::Object?) → core::double?}.{core::double::+}(0.5){(core::num) → core::double}){(core::String, core::double) → void};
+  let final self::Class<core::String> #t9 = c in let final core::int #t10 = 0 in #t9.{self::Class::[]=}(#t10, #t9.{self::Class::[]}(#t10){(core::int) → self::Class<core::String>}.{self::Class::+}(c){(self::Class<core::String>) → self::Class<core::String>}){(core::int, self::Class<core::String>) → void};
+  core::print("DynamicInvocation");
+  let final dynamic #t11 = dyn in let final core::int #t12 = 0 in #t11{dynamic}.[]=(#t12, #t11{dynamic}.[](#t12){dynamic}.+(42));
+  core::print("DynamicInvocation (Never)");
+  let final Never #t13 = never in let final core::int #t14 = 0 in #t13{Never}.[]=(#t14, #t13{Never}.[](#t14){Never}.+(42));
+  core::print("DynamicInvocation (Invalid)");
+  let final invalid-type #t15 = let final<BottomType> #t16 = invalid-expression "pkg/front_end/testcases/none/operator.dart:126:11: Error: Too few positional arguments: 1 required, 0 given.
+  c.method()[0] += 42;
+          ^" in c.{self::Class::method}{<inapplicable>}.(){() → invalid-type} in let final core::int #t17 = 0 in #t15{<invalid>}.[]=(#t17, #t15{<invalid>}.[](#t17){<invalid>}.+(42));
+  core::print("DynamicInvocation (Unresolved)");
+  let final dynamic #t18 = invalid-expression "pkg/front_end/testcases/none/operator.dart:129:3: Error: Getter not found: 'string'.
+  string[0] += 42;
+  ^^^^^^" in let final core::int #t19 = 0 in #t18{dynamic}.[]=(#t19, #t18{dynamic}.[](#t19){dynamic}.+(42));
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/none/operator.dart.textual_outline.expect b/pkg/front_end/testcases/none/operator.dart.textual_outline.expect
new file mode 100644
index 0000000..f2e598e
--- /dev/null
+++ b/pkg/front_end/testcases/none/operator.dart.textual_outline.expect
@@ -0,0 +1,19 @@
+class Class<T> {
+  Class<T> operator +(Class<T> other) => other;
+  Class<T> operator -() => this;
+  Class<T> operator [](int index) => this;
+  operator []=(int index, Class<T> value) {}
+  int method(double o) => 42;
+}
+
+add(num n, int i, double d, Class<String> c, dynamic dyn, Never never,
+    String string) {}
+unaryMinus(num n, int i, double d, Class<String> c, dynamic dyn, Never never,
+    String string) {}
+indexGet(List<int> list, Map<String, double> map, Class<String> c, dynamic dyn,
+    Never never, String string) {}
+indexSet(List<int> list, Map<String, double> map, Class<String> c, dynamic dyn,
+    Never never) {}
+compound(List<int> list, Map<String, double> map, Class<String> c, dynamic dyn,
+    Never never) {}
+main() {}
diff --git a/pkg/front_end/testcases/none/operator.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/none/operator.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..d19339d
--- /dev/null
+++ b/pkg/front_end/testcases/none/operator.dart.textual_outline_modelled.expect
@@ -0,0 +1,20 @@
+add(num n, int i, double d, Class<String> c, dynamic dyn, Never never,
+    String string) {}
+
+class Class<T> {
+  Class<T> operator +(Class<T> other) => other;
+  Class<T> operator -() => this;
+  Class<T> operator [](int index) => this;
+  int method(double o) => 42;
+  operator []=(int index, Class<T> value) {}
+}
+
+compound(List<int> list, Map<String, double> map, Class<String> c, dynamic dyn,
+    Never never) {}
+indexGet(List<int> list, Map<String, double> map, Class<String> c, dynamic dyn,
+    Never never, String string) {}
+indexSet(List<int> list, Map<String, double> map, Class<String> c, dynamic dyn,
+    Never never) {}
+main() {}
+unaryMinus(num n, int i, double d, Class<String> c, dynamic dyn, Never never,
+    String string) {}
diff --git a/pkg/front_end/testcases/none/operator.dart.weak.expect b/pkg/front_end/testcases/none/operator.dart.weak.expect
new file mode 100644
index 0000000..92c34a3
--- /dev/null
+++ b/pkg/front_end/testcases/none/operator.dart.weak.expect
@@ -0,0 +1,164 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/operator.dart:48:10: Error: The operator '-' isn't defined for the class 'String'.
+// Try correcting the operator to an existing operator, or defining a '-' operator.
+//   string - 42;
+//          ^
+//
+// pkg/front_end/testcases/none/operator.dart:66:12: Error: Too few positional arguments: 1 required, 0 given.
+//   -c.method();
+//            ^
+//
+// pkg/front_end/testcases/none/operator.dart:69:3: Error: The operator 'unary-' isn't defined for the class 'String'.
+// Try correcting the operator to an existing operator, or defining a 'unary-' operator.
+//   -string;
+//   ^
+//
+// pkg/front_end/testcases/none/operator.dart:86:11: Error: Too few positional arguments: 1 required, 0 given.
+//   c.method()[0];
+//           ^
+//
+// pkg/front_end/testcases/none/operator.dart:109:3: Error: Getter not found: 'string'.
+//   string[0] = 42;
+//   ^^^^^^
+//
+// pkg/front_end/testcases/none/operator.dart:106:11: Error: Too few positional arguments: 1 required, 0 given.
+//   c.method()[0] = 42;
+//           ^
+//
+// pkg/front_end/testcases/none/operator.dart:129:3: Error: Getter not found: 'string'.
+//   string[0] += 42;
+//   ^^^^^^
+//
+// pkg/front_end/testcases/none/operator.dart:116:14: Error: Operator '+' cannot be called on 'double?' because it is potentially null.
+//   map['foo'] += 0.5;
+//              ^
+//
+// pkg/front_end/testcases/none/operator.dart:126:11: Error: Too few positional arguments: 1 required, 0 given.
+//   c.method()[0] += 42;
+//           ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T%>
+    : super core::Object::•()
+    ;
+  operator +(generic-covariant-impl self::Class<self::Class::T%> other) → self::Class<self::Class::T%>
+    return other;
+  operator unary-() → self::Class<self::Class::T%>
+    return this;
+  operator [](core::int index) → self::Class<self::Class::T%>
+    return this;
+  operator []=(core::int index, generic-covariant-impl self::Class<self::Class::T%> value) → void {}
+  method method(core::double o) → core::int
+    return 42;
+}
+static method add(core::num n, core::int i, core::double d, self::Class<core::String> c, dynamic dyn, Never never, core::String string) → dynamic {
+  core::print("InstanceInvocation");
+  n.{core::num::+}(n){(core::num) → core::num};
+  n.{core::num::+}(i){(core::num) → core::num};
+  n.{core::num::+}(d){(core::num) → core::double};
+  n.{core::num::+}(dyn as{TypeError,ForDynamic,ForNonNullableByDefault} core::num){(core::num) → core::num};
+  core::print("InstanceInvocation");
+  i.{core::num::+}(n){(core::num) → core::num};
+  i.{core::num::+}(i){(core::num) → core::int};
+  i.{core::num::+}(d){(core::num) → core::double};
+  i.{core::num::+}(dyn as{TypeError,ForDynamic,ForNonNullableByDefault} core::num){(core::num) → core::num};
+  core::print("InstanceInvocation");
+  d.{core::double::+}(n){(core::num) → core::double};
+  d.{core::double::+}(i){(core::num) → core::double};
+  d.{core::double::+}(d){(core::num) → core::double};
+  i.{core::num::+}(dyn as{TypeError,ForDynamic,ForNonNullableByDefault} core::num){(core::num) → core::num};
+  core::print("InstanceInvocation");
+  c.{self::Class::+}(c){(self::Class<core::String>) → self::Class<core::String>};
+  c.{self::Class::+}(dyn as{TypeError,ForDynamic,ForNonNullableByDefault} self::Class<core::String>){(self::Class<core::String>) → self::Class<core::String>};
+  core::print("DynamicInvocation");
+  dyn{dynamic}.+(n);
+  core::print("DynamicInvocation (Never)");
+  let final Never #t1 = (let final Never #t2 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")){Never}.+(n) in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  core::print("DynamicInvocation (Invalid)");
+  invalid-expression "pkg/front_end/testcases/none/operator.dart:48:10: Error: The operator '-' isn't defined for the class 'String'.
+Try correcting the operator to an existing operator, or defining a '-' operator.
+  string - 42;
+         ^";
+}
+static method unaryMinus(core::num n, core::int i, core::double d, self::Class<core::String> c, dynamic dyn, Never never, core::String string) → dynamic {
+  core::print("InstanceInvocation");
+  n.{core::num::unary-}(){() → core::num};
+  i.{core::int::unary-}(){() → core::int};
+  d.{core::double::unary-}(){() → core::double};
+  c.{self::Class::unary-}(){() → self::Class<core::String>};
+  core::print("DynamicInvocation");
+  dyn{dynamic}.unary-();
+  core::print("DynamicInvocation (Never)");
+  let final Never #t3 = (let final Never #t4 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")){Never}.unary-() in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  core::print("DynamicInvocation (Invalid)");
+  (let final<BottomType> #t5 = invalid-expression "pkg/front_end/testcases/none/operator.dart:66:12: Error: Too few positional arguments: 1 required, 0 given.
+  -c.method();
+           ^" in c.{self::Class::method}{<inapplicable>}.(){() → invalid-type}){<invalid>}.unary-();
+  core::print("DynamicInvocation (Unresolved)");
+  invalid-expression "pkg/front_end/testcases/none/operator.dart:69:3: Error: The operator 'unary-' isn't defined for the class 'String'.
+Try correcting the operator to an existing operator, or defining a 'unary-' operator.
+  -string;
+  ^";
+}
+static method indexGet(core::List<core::int> list, core::Map<core::String, core::double> map, self::Class<core::String> c, dynamic dyn, Never never, core::String string) → dynamic {
+  core::print("InstanceInvocation");
+  list.{core::List::[]}(0){(core::int) → core::int};
+  map.{core::Map::[]}("foo"){(core::Object?) → core::double?};
+  c.{self::Class::[]}(0){(core::int) → self::Class<core::String>};
+  core::print("DynamicInvocation");
+  dyn{dynamic}.[](0);
+  core::print("DynamicInvocation (Never)");
+  let final Never #t6 = (let final Never #t7 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")){Never}.[](0) in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  core::print("DynamicInvocation (Invalid)");
+  (let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/none/operator.dart:86:11: Error: Too few positional arguments: 1 required, 0 given.
+  c.method()[0];
+          ^" in c.{self::Class::method}{<inapplicable>}.(){() → invalid-type}){<invalid>}.[](0);
+  core::print("DynamicInvocation (Unresolved)");
+  string.{core::String::[]}(0){(core::int) → core::String};
+}
+static method indexSet(core::List<core::int> list, core::Map<core::String, core::double> map, self::Class<core::String> c, dynamic dyn, Never never) → dynamic {
+  core::print("InstanceInvocation");
+  list.{core::List::[]=}(0, 42){(core::int, core::int) → void};
+  map.{core::Map::[]=}("foo", 0.5){(core::String, core::double) → void};
+  c.{self::Class::[]=}(0, c){(core::int, self::Class<core::String>) → void};
+  core::print("DynamicInvocation");
+  dyn{dynamic}.[]=(0, 42);
+  core::print("DynamicInvocation (Never)");
+  (let final Never #t9 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")){Never}.[]=(0, 42);
+  core::print("DynamicInvocation (Invalid)");
+  (let final<BottomType> #t10 = invalid-expression "pkg/front_end/testcases/none/operator.dart:106:11: Error: Too few positional arguments: 1 required, 0 given.
+  c.method()[0] = 42;
+          ^" in c.{self::Class::method}{<inapplicable>}.(){() → invalid-type}){<invalid>}.[]=(0, 42);
+  core::print("DynamicInvocation (Unresolved)");
+  invalid-expression "pkg/front_end/testcases/none/operator.dart:109:3: Error: Getter not found: 'string'.
+  string[0] = 42;
+  ^^^^^^"{dynamic}.[]=(0, 42);
+}
+static method compound(core::List<core::int> list, core::Map<core::String, core::double> map, self::Class<core::String> c, dynamic dyn, Never never) → dynamic {
+  core::print("InstanceInvocation");
+  let final core::List<core::int> #t11 = list in let final core::int #t12 = 0 in #t11.{core::List::[]=}(#t12, #t11.{core::List::[]}(#t12){(core::int) → core::int}.{core::num::+}(42){(core::num) → core::int}){(core::int, core::int) → void};
+  let final core::Map<core::String, core::double> #t13 = map in let final core::String #t14 = "foo" in #t13.{core::Map::[]=}(#t14, let final<BottomType> #t15 = invalid-expression "pkg/front_end/testcases/none/operator.dart:116:14: Error: Operator '+' cannot be called on 'double?' because it is potentially null.
+  map['foo'] += 0.5;
+             ^" in #t13.{core::Map::[]}(#t14){(core::Object?) → core::double?}.{core::double::+}(0.5){(core::num) → core::double}){(core::String, core::double) → void};
+  let final self::Class<core::String> #t16 = c in let final core::int #t17 = 0 in #t16.{self::Class::[]=}(#t17, #t16.{self::Class::[]}(#t17){(core::int) → self::Class<core::String>}.{self::Class::+}(c){(self::Class<core::String>) → self::Class<core::String>}){(core::int, self::Class<core::String>) → void};
+  core::print("DynamicInvocation");
+  let final dynamic #t18 = dyn in let final core::int #t19 = 0 in #t18{dynamic}.[]=(#t19, #t18{dynamic}.[](#t19){dynamic}.+(42));
+  core::print("DynamicInvocation (Never)");
+  let final Never #t20 = let final Never #t21 = let final Never #t22 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.") in let final core::int #t23 = 0 in #t21{Never}.[]=(#t23, #t21{Never}.[](#t23){Never}.+(42)) in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  core::print("DynamicInvocation (Invalid)");
+  let final invalid-type #t24 = let final<BottomType> #t25 = invalid-expression "pkg/front_end/testcases/none/operator.dart:126:11: Error: Too few positional arguments: 1 required, 0 given.
+  c.method()[0] += 42;
+          ^" in c.{self::Class::method}{<inapplicable>}.(){() → invalid-type} in let final core::int #t26 = 0 in #t24{<invalid>}.[]=(#t26, #t24{<invalid>}.[](#t26){<invalid>}.+(42));
+  core::print("DynamicInvocation (Unresolved)");
+  let final dynamic #t27 = invalid-expression "pkg/front_end/testcases/none/operator.dart:129:3: Error: Getter not found: 'string'.
+  string[0] += 42;
+  ^^^^^^" in let final core::int #t28 = 0 in #t27{dynamic}.[]=(#t28, #t27{dynamic}.[](#t28){dynamic}.+(42));
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/none/property_get.dart b/pkg/front_end/testcases/none/property_get.dart
new file mode 100644
index 0000000..15baea3
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_get.dart
@@ -0,0 +1,116 @@
+// 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.md file.
+
+class Class1 {
+  int field;
+
+  Class1(this.field);
+
+  int method(double o) => 0;
+
+  static int staticField = 42;
+
+  static int staticMethod(double o) => 0;
+}
+
+int topLevelField = 42;
+
+int topLevelMethod(double o) => 0;
+
+class Class2<T> {
+  T field;
+
+  Class2(this.field);
+
+  int call() => 42;
+}
+
+const String string = 'foo';
+const int stringLength = string.length;
+
+const dynamic dynamicString = 'foo';
+const int dynamicStringLength = dynamicString.length;
+
+test<T1 extends Function, T2 extends int Function()>(
+    Class1 nonNullableClass1,
+    Class1? nullableClass1,
+    dynamic dyn,
+    Never never,
+    Class2<String> nonNullableClass2,
+    Class2<String>? nullableClass2,
+    Function nonNullableFunction,
+    Function? nullableFunction,
+    int Function() nonNullableFunctionType,
+    int Function()? nullableFunctionType,
+    T1 nonNullableTypeVariable1,
+    T1? nullableTypeVariable1,
+    T2 nonNullableTypeVariable2,
+    T2? nullableTypeVariable2) {
+  print('InstanceGet');
+  nonNullableClass1.field;
+  nullableClass1?.field;
+  nonNullableClass2.field;
+  nullableClass2?.field;
+  const dynamic instance_get = nullableClass1.field;
+  print(instance_get);
+
+  print('InstanceTearOff');
+  nonNullableClass1.method;
+  nullableClass1?.method;
+  nonNullableClass2.call;
+  nullableClass2?.call;
+  const dynamic instance_tearOff = nonNullableClass1.method;
+  print(instance_tearOff);
+
+  Function f1 = nonNullableClass2;
+  Function? f2 = nullableClass2;
+
+  print('StaticGet');
+  Class1.staticField;
+  topLevelField;
+
+  print('StaticTearOff');
+  Class1.staticMethod;
+  topLevelMethod;
+  const dynamic static_tearOff = topLevelMethod;
+  print(static_tearOff);
+
+  print('DynamicGet');
+  dyn.field;
+  dyn?.field;
+  const dynamic dyn_get = dyn.field;
+  print(dyn_get);
+
+  print('InstanceGet (Object)');
+  dyn.hashCode;
+  nullableClass1.hashCode;
+
+  print('InstanceGetTearOff (Object)');
+  dyn.toString;
+  nullableClass1.toString;
+
+  print('DynamicGet (Never)');
+  never.field;
+  never.hashCode;
+
+  print('FunctionTearOff');
+  nonNullableFunction.call;
+  nullableFunction?.call;
+  nonNullableFunctionType.call;
+  nullableFunctionType?.call;
+  nonNullableTypeVariable1.call;
+  nullableTypeVariable1?.call;
+  nonNullableTypeVariable2.call;
+  nullableTypeVariable2?.call;
+  const dynamic function_tearOff = nonNullableFunction.call;
+  print(function_tearOff);
+
+  print('DynamicGet (Invalid)');
+  nonNullableClass1.method().field;
+
+  print('DynamicGet (Unresolved)');
+  nonNullableClass1.unresolved;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/none/property_get.dart.outline.expect b/pkg/front_end/testcases/none/property_get.dart.outline.expect
new file mode 100644
index 0000000..06c8396
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_get.dart.outline.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  field core::int field;
+  static field core::int staticField;
+  constructor •(core::int field) → self::Class1
+    ;
+  method method(core::double o) → core::int
+    ;
+  static method staticMethod(core::double o) → core::int
+    ;
+}
+class Class2<T extends core::Object? = dynamic> extends core::Object {
+  generic-covariant-impl field self::Class2::T% field;
+  constructor •(self::Class2::T% field) → self::Class2<self::Class2::T%>
+    ;
+  method call() → core::int
+    ;
+}
+static field core::int topLevelField;
+static const field core::String string = "foo";
+static const field core::int stringLength = self::string.{core::String::length}{core::int};
+static const field dynamic dynamicString = "foo";
+static const field core::int dynamicStringLength = self::dynamicString{dynamic}.length as{TypeError,ForDynamic,ForNonNullableByDefault} core::int;
+static method topLevelMethod(core::double o) → core::int
+  ;
+static method test<T1 extends core::Function = core::Function, T2 extends () → core::int = () → core::int>(self::Class1 nonNullableClass1, self::Class1? nullableClass1, dynamic dyn, Never never, self::Class2<core::String> nonNullableClass2, self::Class2<core::String>? nullableClass2, core::Function nonNullableFunction, core::Function? nullableFunction, () → core::int nonNullableFunctionType, () →? core::int nullableFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2) → dynamic
+  ;
+static method main() → dynamic
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: InstanceGet @ org-dartlang-testcase:///property_get.dart:30:33 -> IntConstant(3)
+Evaluated: AsExpression @ org-dartlang-testcase:///property_get.dart:33:47 -> IntConstant(3)
+Extra constant evaluation: evaluated: 2, effectively constant: 2
diff --git a/pkg/front_end/testcases/none/property_get.dart.strong.expect b/pkg/front_end/testcases/none/property_get.dart.strong.expect
new file mode 100644
index 0000000..b1397c7
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_get.dart.strong.expect
@@ -0,0 +1,149 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/property_get.dart:55:32: Error: Not a constant expression.
+//   const dynamic instance_get = nullableClass1.field;
+//                                ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/property_get.dart:63:36: Error: Not a constant expression.
+//   const dynamic instance_tearOff = nonNullableClass1.method;
+//                                    ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/property_get.dart:82:27: Error: Not a constant expression.
+//   const dynamic dyn_get = dyn.field;
+//                           ^^^
+//
+// pkg/front_end/testcases/none/property_get.dart:106:36: Error: Not a constant expression.
+//   const dynamic function_tearOff = nonNullableFunction.call;
+//                                    ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/property_get.dart:67:18: Error: Can't tear off method 'call' from a potentially null value.
+//   Function? f2 = nullableClass2;
+//                  ^
+//
+// pkg/front_end/testcases/none/property_get.dart:110:27: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass1.method().field;
+//                           ^
+//
+// pkg/front_end/testcases/none/property_get.dart:113:21: Error: The getter 'unresolved' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/none/property_get.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'unresolved'.
+//   nonNullableClass1.unresolved;
+//                     ^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  field core::int field;
+  static field core::int staticField = 42;
+  constructor •(core::int field) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  method method(core::double o) → core::int
+    return 0;
+  static method staticMethod(core::double o) → core::int
+    return 0;
+}
+class Class2<T extends core::Object? = dynamic> extends core::Object {
+  generic-covariant-impl field self::Class2::T% field;
+  constructor •(self::Class2::T% field) → self::Class2<self::Class2::T%>
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  method call() → core::int
+    return 42;
+}
+static field core::int topLevelField = 42;
+static const field core::String string = #C1;
+static const field core::int stringLength = #C2;
+static const field dynamic dynamicString = #C1;
+static const field core::int dynamicStringLength = #C2;
+static method topLevelMethod(core::double o) → core::int
+  return 0;
+static method test<T1 extends core::Function = core::Function, T2 extends () → core::int = () → core::int>(self::Class1 nonNullableClass1, self::Class1? nullableClass1, dynamic dyn, Never never, self::Class2<core::String> nonNullableClass2, self::Class2<core::String>? nullableClass2, core::Function nonNullableFunction, core::Function? nullableFunction, () → core::int nonNullableFunctionType, () →? core::int nullableFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2) → dynamic {
+  core::print("InstanceGet");
+  nonNullableClass1.{self::Class1::field}{core::int};
+  let final self::Class1? #t1 = nullableClass1 in #t1 == null ?{core::int?} null : #t1{self::Class1}.{self::Class1::field}{core::int};
+  nonNullableClass2.{self::Class2::field}{core::String};
+  let final self::Class2<core::String>? #t2 = nullableClass2 in #t2 == null ?{core::String?} null : #t2{self::Class2<core::String>}.{self::Class2::field}{core::String};
+  const dynamic instance_get = invalid-expression "pkg/front_end/testcases/none/property_get.dart:55:32: Error: Not a constant expression.
+  const dynamic instance_get = nullableClass1.field;
+                               ^^^^^^^^^^^^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/property_get.dart:55:32: Error: Not a constant expression.
+  const dynamic instance_get = nullableClass1.field;
+                               ^^^^^^^^^^^^^^");
+  core::print("InstanceTearOff");
+  nonNullableClass1.{self::Class1::method}{(core::double) → core::int};
+  let final self::Class1? #t3 = nullableClass1 in #t3 == null ?{(core::double) →? core::int} null : #t3{self::Class1}.{self::Class1::method}{(core::double) → core::int};
+  nonNullableClass2.{self::Class2::call}{() → core::int};
+  let final self::Class2<core::String>? #t4 = nullableClass2 in #t4 == null ?{() →? core::int} null : #t4{self::Class2<core::String>}.{self::Class2::call}{() → core::int};
+  const dynamic instance_tearOff = invalid-expression "pkg/front_end/testcases/none/property_get.dart:63:36: Error: Not a constant expression.
+  const dynamic instance_tearOff = nonNullableClass1.method;
+                                   ^^^^^^^^^^^^^^^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/property_get.dart:63:36: Error: Not a constant expression.
+  const dynamic instance_tearOff = nonNullableClass1.method;
+                                   ^^^^^^^^^^^^^^^^^");
+  core::Function f1 = let final self::Class2<core::String> #t5 = nonNullableClass2 in #t5 == null ?{() → core::int} null : #t5.{self::Class2::call};
+  core::Function? f2 = let final<BottomType> #t6 = invalid-expression "pkg/front_end/testcases/none/property_get.dart:67:18: Error: Can't tear off method 'call' from a potentially null value.
+  Function? f2 = nullableClass2;
+                 ^" in nullableClass2 as{TypeError} core::Function?;
+  core::print("StaticGet");
+  self::Class1::staticField;
+  self::topLevelField;
+  core::print("StaticTearOff");
+  #C3;
+  #C4;
+  core::print(#C4);
+  core::print("DynamicGet");
+  dyn{dynamic}.field;
+  let final dynamic #t7 = dyn in #t7 == null ?{dynamic} null : #t7{dynamic}.field;
+  const dynamic dyn_get = invalid-expression "pkg/front_end/testcases/none/property_get.dart:82:27: Error: Not a constant expression.
+  const dynamic dyn_get = dyn.field;
+                          ^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/property_get.dart:82:27: Error: Not a constant expression.
+  const dynamic dyn_get = dyn.field;
+                          ^^^");
+  core::print("InstanceGet (Object)");
+  dyn.{core::Object::hashCode}{core::int};
+  nullableClass1.{core::Object::hashCode}{core::int};
+  core::print("InstanceGetTearOff (Object)");
+  dyn.{core::Object::toString}{() → core::String};
+  nullableClass1.{core::Object::toString}{() → core::String};
+  core::print("DynamicGet (Never)");
+  never{Never}.field;
+  never{Never}.hashCode;
+  core::print("FunctionTearOff");
+  nonNullableFunction.call;
+  let final core::Function? #t8 = nullableFunction in #t8 == null ?{core::Function?} null : #t8{core::Function}.call;
+  nonNullableFunctionType.call;
+  let final () →? core::int #t9 = nullableFunctionType in #t9 == null ?{() →? core::int} null : #t9{() → core::int}.call;
+  nonNullableTypeVariable1.call;
+  let final self::test::T1? #t10 = nullableTypeVariable1 in #t10 == null ?{self::test::T1?} null : #t10{self::test::T1}.call;
+  nonNullableTypeVariable2.call;
+  let final self::test::T2? #t11 = nullableTypeVariable2 in #t11 == null ?{self::test::T2?} null : #t11{self::test::T2}.call;
+  const dynamic function_tearOff = invalid-expression "pkg/front_end/testcases/none/property_get.dart:106:36: Error: Not a constant expression.
+  const dynamic function_tearOff = nonNullableFunction.call;
+                                   ^^^^^^^^^^^^^^^^^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/property_get.dart:106:36: Error: Not a constant expression.
+  const dynamic function_tearOff = nonNullableFunction.call;
+                                   ^^^^^^^^^^^^^^^^^^^");
+  core::print("DynamicGet (Invalid)");
+  (let final<BottomType> #t12 = invalid-expression "pkg/front_end/testcases/none/property_get.dart:110:27: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass1.method().field;
+                          ^" in nonNullableClass1.{self::Class1::method}{<inapplicable>}.(){() → invalid-type}){<invalid>}.field;
+  core::print("DynamicGet (Unresolved)");
+  invalid-expression "pkg/front_end/testcases/none/property_get.dart:113:21: Error: The getter 'unresolved' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/none/property_get.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'unresolved'.
+  nonNullableClass1.unresolved;
+                    ^^^^^^^^^^";
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = "foo"
+  #C2 = 3
+  #C3 = tearoff self::Class1::staticMethod
+  #C4 = tearoff self::topLevelMethod
+}
diff --git a/pkg/front_end/testcases/none/property_get.dart.textual_outline.expect b/pkg/front_end/testcases/none/property_get.dart.textual_outline.expect
new file mode 100644
index 0000000..3e3ed79
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_get.dart.textual_outline.expect
@@ -0,0 +1,37 @@
+class Class1 {
+  int field;
+  Class1(this.field);
+  int method(double o) => 0;
+  static int staticField = 42;
+  static int staticMethod(double o) => 0;
+}
+
+int topLevelField = 42;
+int topLevelMethod(double o) => 0;
+
+class Class2<T> {
+  T field;
+  Class2(this.field);
+  int call() => 42;
+}
+
+const String string = 'foo';
+const int stringLength = string.length;
+const dynamic dynamicString = 'foo';
+const int dynamicStringLength = dynamicString.length;
+test<T1 extends Function, T2 extends int Function()>(
+    Class1 nonNullableClass1,
+    Class1? nullableClass1,
+    dynamic dyn,
+    Never never,
+    Class2<String> nonNullableClass2,
+    Class2<String>? nullableClass2,
+    Function nonNullableFunction,
+    Function? nullableFunction,
+    int Function() nonNullableFunctionType,
+    int Function()? nullableFunctionType,
+    T1 nonNullableTypeVariable1,
+    T1? nullableTypeVariable1,
+    T2 nonNullableTypeVariable2,
+    T2? nullableTypeVariable2) {}
+main() {}
diff --git a/pkg/front_end/testcases/none/property_get.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/none/property_get.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..cb56e8a
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_get.dart.textual_outline_modelled.expect
@@ -0,0 +1,36 @@
+class Class1 {
+  Class1(this.field);
+  int field;
+  int method(double o) => 0;
+  static int staticField = 42;
+  static int staticMethod(double o) => 0;
+}
+
+class Class2<T> {
+  Class2(this.field);
+  T field;
+  int call() => 42;
+}
+
+const String string = 'foo';
+const dynamic dynamicString = 'foo';
+const int dynamicStringLength = dynamicString.length;
+const int stringLength = string.length;
+int topLevelField = 42;
+int topLevelMethod(double o) => 0;
+main() {}
+test<T1 extends Function, T2 extends int Function()>(
+    Class1 nonNullableClass1,
+    Class1? nullableClass1,
+    dynamic dyn,
+    Never never,
+    Class2<String> nonNullableClass2,
+    Class2<String>? nullableClass2,
+    Function nonNullableFunction,
+    Function? nullableFunction,
+    int Function() nonNullableFunctionType,
+    int Function()? nullableFunctionType,
+    T1 nonNullableTypeVariable1,
+    T1? nullableTypeVariable1,
+    T2 nonNullableTypeVariable2,
+    T2? nullableTypeVariable2) {}
diff --git a/pkg/front_end/testcases/none/property_get.dart.weak.expect b/pkg/front_end/testcases/none/property_get.dart.weak.expect
new file mode 100644
index 0000000..d52d9df
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_get.dart.weak.expect
@@ -0,0 +1,150 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/property_get.dart:55:32: Error: Not a constant expression.
+//   const dynamic instance_get = nullableClass1.field;
+//                                ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/property_get.dart:63:36: Error: Not a constant expression.
+//   const dynamic instance_tearOff = nonNullableClass1.method;
+//                                    ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/property_get.dart:82:27: Error: Not a constant expression.
+//   const dynamic dyn_get = dyn.field;
+//                           ^^^
+//
+// pkg/front_end/testcases/none/property_get.dart:106:36: Error: Not a constant expression.
+//   const dynamic function_tearOff = nonNullableFunction.call;
+//                                    ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/property_get.dart:67:18: Error: Can't tear off method 'call' from a potentially null value.
+//   Function? f2 = nullableClass2;
+//                  ^
+//
+// pkg/front_end/testcases/none/property_get.dart:110:27: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass1.method().field;
+//                           ^
+//
+// pkg/front_end/testcases/none/property_get.dart:113:21: Error: The getter 'unresolved' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/none/property_get.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'unresolved'.
+//   nonNullableClass1.unresolved;
+//                     ^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class1 extends core::Object {
+  field core::int field;
+  static field core::int staticField = 42;
+  constructor •(core::int field) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  method method(core::double o) → core::int
+    return 0;
+  static method staticMethod(core::double o) → core::int
+    return 0;
+}
+class Class2<T extends core::Object? = dynamic> extends core::Object {
+  generic-covariant-impl field self::Class2::T% field;
+  constructor •(self::Class2::T% field) → self::Class2<self::Class2::T%>
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  method call() → core::int
+    return 42;
+}
+static field core::int topLevelField = 42;
+static const field core::String string = #C1;
+static const field core::int stringLength = #C2;
+static const field dynamic dynamicString = #C1;
+static const field core::int dynamicStringLength = #C2;
+static method topLevelMethod(core::double o) → core::int
+  return 0;
+static method test<T1 extends core::Function = core::Function, T2 extends () → core::int = () → core::int>(self::Class1 nonNullableClass1, self::Class1? nullableClass1, dynamic dyn, Never never, self::Class2<core::String> nonNullableClass2, self::Class2<core::String>? nullableClass2, core::Function nonNullableFunction, core::Function? nullableFunction, () → core::int nonNullableFunctionType, () →? core::int nullableFunctionType, self::test::T1 nonNullableTypeVariable1, self::test::T1? nullableTypeVariable1, self::test::T2 nonNullableTypeVariable2, self::test::T2? nullableTypeVariable2) → dynamic {
+  core::print("InstanceGet");
+  nonNullableClass1.{self::Class1::field}{core::int};
+  let final self::Class1? #t1 = nullableClass1 in #t1 == null ?{core::int?} null : #t1{self::Class1}.{self::Class1::field}{core::int};
+  nonNullableClass2.{self::Class2::field}{core::String};
+  let final self::Class2<core::String>? #t2 = nullableClass2 in #t2 == null ?{core::String?} null : #t2{self::Class2<core::String>}.{self::Class2::field}{core::String};
+  const dynamic instance_get = invalid-expression "pkg/front_end/testcases/none/property_get.dart:55:32: Error: Not a constant expression.
+  const dynamic instance_get = nullableClass1.field;
+                               ^^^^^^^^^^^^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/property_get.dart:55:32: Error: Not a constant expression.
+  const dynamic instance_get = nullableClass1.field;
+                               ^^^^^^^^^^^^^^");
+  core::print("InstanceTearOff");
+  nonNullableClass1.{self::Class1::method}{(core::double) → core::int};
+  let final self::Class1? #t3 = nullableClass1 in #t3 == null ?{(core::double) →? core::int} null : #t3{self::Class1}.{self::Class1::method}{(core::double) → core::int};
+  nonNullableClass2.{self::Class2::call}{() → core::int};
+  let final self::Class2<core::String>? #t4 = nullableClass2 in #t4 == null ?{() →? core::int} null : #t4{self::Class2<core::String>}.{self::Class2::call}{() → core::int};
+  const dynamic instance_tearOff = invalid-expression "pkg/front_end/testcases/none/property_get.dart:63:36: Error: Not a constant expression.
+  const dynamic instance_tearOff = nonNullableClass1.method;
+                                   ^^^^^^^^^^^^^^^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/property_get.dart:63:36: Error: Not a constant expression.
+  const dynamic instance_tearOff = nonNullableClass1.method;
+                                   ^^^^^^^^^^^^^^^^^");
+  core::Function f1 = let final self::Class2<core::String> #t5 = nonNullableClass2 in #t5 == null ?{() → core::int} null : #t5.{self::Class2::call};
+  core::Function? f2 = let final<BottomType> #t6 = invalid-expression "pkg/front_end/testcases/none/property_get.dart:67:18: Error: Can't tear off method 'call' from a potentially null value.
+  Function? f2 = nullableClass2;
+                 ^" in nullableClass2 as{TypeError} core::Function?;
+  core::print("StaticGet");
+  self::Class1::staticField;
+  self::topLevelField;
+  core::print("StaticTearOff");
+  #C3;
+  #C4;
+  core::print(#C4);
+  core::print("DynamicGet");
+  dyn{dynamic}.field;
+  let final dynamic #t7 = dyn in #t7 == null ?{dynamic} null : #t7{dynamic}.field;
+  const dynamic dyn_get = invalid-expression "pkg/front_end/testcases/none/property_get.dart:82:27: Error: Not a constant expression.
+  const dynamic dyn_get = dyn.field;
+                          ^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/property_get.dart:82:27: Error: Not a constant expression.
+  const dynamic dyn_get = dyn.field;
+                          ^^^");
+  core::print("InstanceGet (Object)");
+  dyn.{core::Object::hashCode}{core::int};
+  nullableClass1.{core::Object::hashCode}{core::int};
+  core::print("InstanceGetTearOff (Object)");
+  dyn.{core::Object::toString}{() → core::String};
+  nullableClass1.{core::Object::toString}{() → core::String};
+  core::print("DynamicGet (Never)");
+  let final Never #t8 = (let final Never #t9 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")){Never}.field in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  let final Never #t10 = (let final Never #t11 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")){Never}.hashCode in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.");
+  core::print("FunctionTearOff");
+  nonNullableFunction.call;
+  let final core::Function? #t12 = nullableFunction in #t12 == null ?{core::Function?} null : #t12{core::Function}.call;
+  nonNullableFunctionType.call;
+  let final () →? core::int #t13 = nullableFunctionType in #t13 == null ?{() →? core::int} null : #t13{() → core::int}.call;
+  nonNullableTypeVariable1.call;
+  let final self::test::T1? #t14 = nullableTypeVariable1 in #t14 == null ?{self::test::T1?} null : #t14{self::test::T1}.call;
+  nonNullableTypeVariable2.call;
+  let final self::test::T2? #t15 = nullableTypeVariable2 in #t15 == null ?{self::test::T2?} null : #t15{self::test::T2}.call;
+  const dynamic function_tearOff = invalid-expression "pkg/front_end/testcases/none/property_get.dart:106:36: Error: Not a constant expression.
+  const dynamic function_tearOff = nonNullableFunction.call;
+                                   ^^^^^^^^^^^^^^^^^^^";
+  core::print(invalid-expression "pkg/front_end/testcases/none/property_get.dart:106:36: Error: Not a constant expression.
+  const dynamic function_tearOff = nonNullableFunction.call;
+                                   ^^^^^^^^^^^^^^^^^^^");
+  core::print("DynamicGet (Invalid)");
+  (let final<BottomType> #t16 = invalid-expression "pkg/front_end/testcases/none/property_get.dart:110:27: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass1.method().field;
+                          ^" in nonNullableClass1.{self::Class1::method}{<inapplicable>}.(){() → invalid-type}){<invalid>}.field;
+  core::print("DynamicGet (Unresolved)");
+  invalid-expression "pkg/front_end/testcases/none/property_get.dart:113:21: Error: The getter 'unresolved' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/none/property_get.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'unresolved'.
+  nonNullableClass1.unresolved;
+                    ^^^^^^^^^^";
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = "foo"
+  #C2 = 3
+  #C3 = tearoff self::Class1::staticMethod
+  #C4 = tearoff self::topLevelMethod
+}
diff --git a/pkg/front_end/testcases/none/property_set.dart b/pkg/front_end/testcases/none/property_set.dart
new file mode 100644
index 0000000..3af5cd3
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_set.dart
@@ -0,0 +1,35 @@
+// 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.md file.
+
+class Class1 {
+  int field;
+
+  Class1(this.field);
+
+  method(o) {}
+}
+
+test(Class1 nonNullableClass1, Class1? nullableClass1, dynamic dyn,
+    Never never) {
+  print("InstanceSet");
+  nonNullableClass1.field = 42;
+  nullableClass1?.field = 42;
+  const int set_instance_field = nonNullableClass1.field = 42;
+
+  print("DynamicSet");
+  dyn.field = 42;
+  dyn?.field = 42;
+  const int set_dynamic_field = dyn.field = 42;
+
+  print("DynamicSet (Never)");
+  never.field = 42;
+
+  print("DynamicSet (Invalid)");
+  nonNullableClass1.method().field = 42;
+
+  print("DynamicSet (Unresolved)");
+  nonNullableClass1.unresolved = 42;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/none/property_set.dart.outline.expect b/pkg/front_end/testcases/none/property_set.dart.outline.expect
new file mode 100644
index 0000000..d101c9e
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_set.dart.outline.expect
@@ -0,0 +1,15 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  field core::int field;
+  constructor •(core::int field) → self::Class1
+    ;
+  method method(dynamic o) → dynamic
+    ;
+}
+static method test(self::Class1 nonNullableClass1, self::Class1? nullableClass1, dynamic dyn, Never never) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/none/property_set.dart.strong.expect b/pkg/front_end/testcases/none/property_set.dart.strong.expect
new file mode 100644
index 0000000..269667d
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_set.dart.strong.expect
@@ -0,0 +1,67 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/property_set.dart:18:34: Error: Not a constant expression.
+//   const int set_instance_field = nonNullableClass1.field = 42;
+//                                  ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/property_set.dart:18:58: Error: Not a constant expression.
+//   const int set_instance_field = nonNullableClass1.field = 42;
+//                                                          ^
+//
+// pkg/front_end/testcases/none/property_set.dart:23:33: Error: Not a constant expression.
+//   const int set_dynamic_field = dyn.field = 42;
+//                                 ^^^
+//
+// pkg/front_end/testcases/none/property_set.dart:23:43: Error: Not a constant expression.
+//   const int set_dynamic_field = dyn.field = 42;
+//                                           ^
+//
+// pkg/front_end/testcases/none/property_set.dart:29:27: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass1.method().field = 42;
+//                           ^
+//
+// pkg/front_end/testcases/none/property_set.dart:32:21: Error: The setter 'unresolved' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/none/property_set.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'unresolved'.
+//   nonNullableClass1.unresolved = 42;
+//                     ^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  field core::int field;
+  constructor •(core::int field) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  method method(dynamic o) → dynamic {}
+}
+static method test(self::Class1 nonNullableClass1, self::Class1? nullableClass1, dynamic dyn, Never never) → dynamic {
+  core::print("InstanceSet");
+  nonNullableClass1.{self::Class1::field} = 42;
+  let final self::Class1? #t1 = nullableClass1 in #t1 == null ?{core::int?} null : #t1{self::Class1}.{self::Class1::field} = 42;
+  const core::int set_instance_field = invalid-expression "pkg/front_end/testcases/none/property_set.dart:18:58: Error: Not a constant expression.
+  const int set_instance_field = nonNullableClass1.field = 42;
+                                                         ^";
+  core::print("DynamicSet");
+  dyn{dynamic}.field = 42;
+  let final dynamic #t2 = dyn in #t2 == null ?{core::int?} null : #t2{dynamic}.field = 42;
+  const core::int set_dynamic_field = invalid-expression "pkg/front_end/testcases/none/property_set.dart:23:43: Error: Not a constant expression.
+  const int set_dynamic_field = dyn.field = 42;
+                                          ^";
+  core::print("DynamicSet (Never)");
+  never{Never}.field = 42;
+  core::print("DynamicSet (Invalid)");
+  (let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/none/property_set.dart:29:27: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass1.method().field = 42;
+                          ^" in nonNullableClass1.{self::Class1::method}{<inapplicable>}.(){() → invalid-type}){<invalid>}.field = 42;
+  core::print("DynamicSet (Unresolved)");
+  invalid-expression "pkg/front_end/testcases/none/property_set.dart:32:21: Error: The setter 'unresolved' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/none/property_set.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'unresolved'.
+  nonNullableClass1.unresolved = 42;
+                    ^^^^^^^^^^";
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/none/property_set.dart.textual_outline.expect b/pkg/front_end/testcases/none/property_set.dart.textual_outline.expect
new file mode 100644
index 0000000..8c2985d
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_set.dart.textual_outline.expect
@@ -0,0 +1,9 @@
+class Class1 {
+  int field;
+  Class1(this.field);
+  method(o) {}
+}
+
+test(Class1 nonNullableClass1, Class1? nullableClass1, dynamic dyn,
+    Never never) {}
+main() {}
diff --git a/pkg/front_end/testcases/none/property_set.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/none/property_set.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..47012bc
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_set.dart.textual_outline_modelled.expect
@@ -0,0 +1,9 @@
+class Class1 {
+  Class1(this.field);
+  int field;
+  method(o) {}
+}
+
+main() {}
+test(Class1 nonNullableClass1, Class1? nullableClass1, dynamic dyn,
+    Never never) {}
diff --git a/pkg/front_end/testcases/none/property_set.dart.weak.expect b/pkg/front_end/testcases/none/property_set.dart.weak.expect
new file mode 100644
index 0000000..e5cbd88
--- /dev/null
+++ b/pkg/front_end/testcases/none/property_set.dart.weak.expect
@@ -0,0 +1,68 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/property_set.dart:18:34: Error: Not a constant expression.
+//   const int set_instance_field = nonNullableClass1.field = 42;
+//                                  ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/none/property_set.dart:18:58: Error: Not a constant expression.
+//   const int set_instance_field = nonNullableClass1.field = 42;
+//                                                          ^
+//
+// pkg/front_end/testcases/none/property_set.dart:23:33: Error: Not a constant expression.
+//   const int set_dynamic_field = dyn.field = 42;
+//                                 ^^^
+//
+// pkg/front_end/testcases/none/property_set.dart:23:43: Error: Not a constant expression.
+//   const int set_dynamic_field = dyn.field = 42;
+//                                           ^
+//
+// pkg/front_end/testcases/none/property_set.dart:29:27: Error: Too few positional arguments: 1 required, 0 given.
+//   nonNullableClass1.method().field = 42;
+//                           ^
+//
+// pkg/front_end/testcases/none/property_set.dart:32:21: Error: The setter 'unresolved' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/none/property_set.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'unresolved'.
+//   nonNullableClass1.unresolved = 42;
+//                     ^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class1 extends core::Object {
+  field core::int field;
+  constructor •(core::int field) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  method method(dynamic o) → dynamic {}
+}
+static method test(self::Class1 nonNullableClass1, self::Class1? nullableClass1, dynamic dyn, Never never) → dynamic {
+  core::print("InstanceSet");
+  nonNullableClass1.{self::Class1::field} = 42;
+  let final self::Class1? #t1 = nullableClass1 in #t1 == null ?{core::int?} null : #t1{self::Class1}.{self::Class1::field} = 42;
+  const core::int set_instance_field = invalid-expression "pkg/front_end/testcases/none/property_set.dart:18:58: Error: Not a constant expression.
+  const int set_instance_field = nonNullableClass1.field = 42;
+                                                         ^";
+  core::print("DynamicSet");
+  dyn{dynamic}.field = 42;
+  let final dynamic #t2 = dyn in #t2 == null ?{core::int?} null : #t2{dynamic}.field = 42;
+  const core::int set_dynamic_field = invalid-expression "pkg/front_end/testcases/none/property_set.dart:23:43: Error: Not a constant expression.
+  const int set_dynamic_field = dyn.field = 42;
+                                          ^";
+  core::print("DynamicSet (Never)");
+  (let final Never #t3 = never in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`.")){Never}.field = 42;
+  core::print("DynamicSet (Invalid)");
+  (let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/none/property_set.dart:29:27: Error: Too few positional arguments: 1 required, 0 given.
+  nonNullableClass1.method().field = 42;
+                          ^" in nonNullableClass1.{self::Class1::method}{<inapplicable>}.(){() → invalid-type}){<invalid>}.field = 42;
+  core::print("DynamicSet (Unresolved)");
+  invalid-expression "pkg/front_end/testcases/none/property_set.dart:32:21: Error: The setter 'unresolved' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/none/property_set.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'unresolved'.
+  nonNullableClass1.unresolved = 42;
+                    ^^^^^^^^^^";
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/none/tearoff_opt_out.dart b/pkg/front_end/testcases/none/tearoff_opt_out.dart
new file mode 100644
index 0000000..e34a1ab
--- /dev/null
+++ b/pkg/front_end/testcases/none/tearoff_opt_out.dart
@@ -0,0 +1,15 @@
+// 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.md file.
+
+// @dart=2.9
+
+class Class {
+  void call() {}
+}
+
+test(Class c) {
+  Function f = c;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/none/tearoff_opt_out.dart.outline.expect b/pkg/front_end/testcases/none/tearoff_opt_out.dart.outline.expect
new file mode 100644
index 0000000..236deb6
--- /dev/null
+++ b/pkg/front_end/testcases/none/tearoff_opt_out.dart.outline.expect
@@ -0,0 +1,31 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/tearoff_opt_out.dart:5:1: Error: A library can't opt out of null safety by default, when using sound null safety.
+// // @dart=2.9
+// ^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    ;
+  method call() → void
+    ;
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+static method test(self::Class* c) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/none/tearoff_opt_out.dart.strong.expect b/pkg/front_end/testcases/none/tearoff_opt_out.dart.strong.expect
new file mode 100644
index 0000000..51270b9
--- /dev/null
+++ b/pkg/front_end/testcases/none/tearoff_opt_out.dart.strong.expect
@@ -0,0 +1,31 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/tearoff_opt_out.dart:5:1: Error: A library can't opt out of null safety by default, when using sound null safety.
+// // @dart=2.9
+// ^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  method call() → void {}
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+static method test(self::Class* c) → dynamic {
+  core::Function* f = let final self::Class* #t1 = c in #t1 == null ?{() →* void} null : #t1.{self::Class::call};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/none/tearoff_opt_out.dart.strong.transformed.expect b/pkg/front_end/testcases/none/tearoff_opt_out.dart.strong.transformed.expect
new file mode 100644
index 0000000..51270b9
--- /dev/null
+++ b/pkg/front_end/testcases/none/tearoff_opt_out.dart.strong.transformed.expect
@@ -0,0 +1,31 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/none/tearoff_opt_out.dart:5:1: Error: A library can't opt out of null safety by default, when using sound null safety.
+// // @dart=2.9
+// ^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  method call() → void {}
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+static method test(self::Class* c) → dynamic {
+  core::Function* f = let final self::Class* #t1 = c in #t1 == null ?{() →* void} null : #t1.{self::Class::call};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/none/tearoff_opt_out.dart.textual_outline.expect b/pkg/front_end/testcases/none/tearoff_opt_out.dart.textual_outline.expect
new file mode 100644
index 0000000..ef070bf
--- /dev/null
+++ b/pkg/front_end/testcases/none/tearoff_opt_out.dart.textual_outline.expect
@@ -0,0 +1,7 @@
+// @dart = 2.9
+class Class {
+  void call() {}
+}
+
+test(Class c) {}
+main() {}
diff --git a/pkg/front_end/testcases/none/tearoff_opt_out.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/none/tearoff_opt_out.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..e7238f8
--- /dev/null
+++ b/pkg/front_end/testcases/none/tearoff_opt_out.dart.textual_outline_modelled.expect
@@ -0,0 +1,7 @@
+// @dart = 2.9
+class Class {
+  void call() {}
+}
+
+main() {}
+test(Class c) {}
diff --git a/pkg/front_end/testcases/none/tearoff_opt_out.dart.weak.expect b/pkg/front_end/testcases/none/tearoff_opt_out.dart.weak.expect
new file mode 100644
index 0000000..7b89feb
--- /dev/null
+++ b/pkg/front_end/testcases/none/tearoff_opt_out.dart.weak.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  method call() → void {}
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+static method test(self::Class* c) → dynamic {
+  core::Function* f = let final self::Class* #t1 = c in #t1 == null ?{() →* void} null : #t1.{self::Class::call};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/none/tearoff_opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/none/tearoff_opt_out.dart.weak.transformed.expect
new file mode 100644
index 0000000..7b89feb
--- /dev/null
+++ b/pkg/front_end/testcases/none/tearoff_opt_out.dart.weak.transformed.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  method call() → void {}
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+static method test(self::Class* c) → dynamic {
+  core::Function* f = let final self::Class* #t1 = c in #t1 == null ?{() →* void} null : #t1.{self::Class::call};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 8df4cda..7ddc27c 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -175,7 +175,12 @@
 nnbd/nullable_object_access: TypeCheckError
 nnbd/nullable_receiver: TypeCheckError
 nnbd/potentially_nullable_access: TypeCheckError
+none/equals: TypeCheckError
 none/mixin_covariant: TypeCheckError
+none/method_invocation: TypeCheckError
+none/operator: TypeCheckError
+none/property_get: TypeCheckError
+none/property_set: TypeCheckError
 rasta/abstract_constructor: RuntimeError
 rasta/bad_constructor_redirection: RuntimeError
 rasta/bad_continue: RuntimeError
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index cdc1183..5607a50 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -24,6 +24,8 @@
 general/callable_type_variable: TypeCheckError
 general/candidate_found: TypeCheckError
 general/cascade: RuntimeError
+general/constants/with_unevaluated_agnostic/const_asserts: TextSerializationFailure
+general/constants/with_unevaluated_agnostic/various: TextSerializationFailure
 general/constructor_initializer_invalid: RuntimeError
 general/covariant_field: TypeCheckError
 general/covariant_generic: RuntimeError
@@ -138,6 +140,8 @@
 general_nnbd_opt_out/type_variable_as_super: RuntimeError
 general_nnbd_opt_out/unsound_promotion: TypeCheckError
 general_nnbd_opt_out/void_methods: RuntimeError
+implicit_getter_calls/getter_call: TextSerializationFailure
+implicit_getter_calls/this_field_call: TextSerializationFailure
 inference/constructors_infer_from_arguments_argument_not_assignable: TypeCheckError
 inference/do_not_infer_overridden_fields_that_explicitly_say_dynamic_infer: TypeCheckError
 inference/downwards_inference_for_each: RuntimeError
@@ -173,7 +177,13 @@
 nnbd/nullable_object_access: TypeCheckError
 nnbd/nullable_receiver: TypeCheckError
 nnbd/potentially_nullable_access: TypeCheckError
+none/equals: TypeCheckError
+none/method_invocation: TypeCheckError
 none/mixin_covariant: TypeCheckError
+none/operator: TypeCheckError
+none/property_get: TypeCheckError
+none/property_set: TypeCheckError
+none/tearoff_opt_out: TextSerializationFailure
 rasta/abstract_constructor: RuntimeError
 rasta/bad_constructor_redirection: RuntimeError
 rasta/bad_continue: RuntimeError
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 23bbcca..2c1b855 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -72,7 +72,12 @@
 nnbd_mixed/messages_with_types_opt_out: TypeCheckError
 nnbd_mixed/super_access/main: Crash # Issue 43864
 nnbd_mixed/super_access/main.no_link: Crash # Issue 43864
+none/equals: TypeCheckError
+none/method_invocation: TypeCheckError
 none/mixin_covariant: TypeCheckError
+none/operator: TypeCheckError
+none/property_get: TypeCheckError
+none/property_set: TypeCheckError
 value_class/simple: RuntimeError # Expected
 value_class/value_extends_non_value: RuntimeError # Expected
 value_class/value_implements_non_value: RuntimeError # Expected
diff --git a/pkg/front_end/tool/_fasta/generate_messages.dart b/pkg/front_end/tool/_fasta/generate_messages.dart
index cd6b870..3d565a8 100644
--- a/pkg/front_end/tool/_fasta/generate_messages.dart
+++ b/pkg/front_end/tool/_fasta/generate_messages.dart
@@ -167,6 +167,7 @@
   // `|` (verbatim) as they always contain a trailing newline that we don't
   // want.
   template = template.trimRight();
+  const String ignoreNotNull = "// ignore: unnecessary_null_comparison";
   var parameters = new Set<String>();
   var conversions = new Set<String>();
   var conversions2 = new Set<String>();
@@ -252,7 +253,8 @@
 
       case "nameOKEmpty":
         parameters.add("String nameOKEmpty");
-        conversions.add("if (nameOKEmpty == null || nameOKEmpty.isEmpty) "
+        conversions.add("$ignoreNotNull\n"
+            "if (nameOKEmpty == null || nameOKEmpty.isEmpty) "
             "nameOKEmpty = '(unnamed)';");
         arguments.add("'nameOKEmpty': nameOKEmpty");
         break;
@@ -296,7 +298,8 @@
 
       case "stringOKEmpty":
         parameters.add("String stringOKEmpty");
-        conversions.add("if (stringOKEmpty == null || stringOKEmpty.isEmpty) "
+        conversions.add("$ignoreNotNull\n"
+            "if (stringOKEmpty == null || stringOKEmpty.isEmpty) "
             "stringOKEmpty = '(empty)';");
         arguments.add("'stringOKEmpty': stringOKEmpty");
         break;
@@ -315,31 +318,33 @@
 
       case "uri":
         parameters.add("Uri uri_");
-        conversions.add("String uri = relativizeUri(uri_);");
+        conversions.add("String? uri = relativizeUri(uri_);");
         arguments.add("'uri': uri_");
         break;
 
       case "uri2":
         parameters.add("Uri uri2_");
-        conversions.add("String uri2 = relativizeUri(uri2_);");
+        conversions.add("String? uri2 = relativizeUri(uri2_);");
         arguments.add("'uri2': uri2_");
         break;
 
       case "uri3":
         parameters.add("Uri uri3_");
-        conversions.add("String uri3 = relativizeUri(uri3_);");
+        conversions.add("String? uri3 = relativizeUri(uri3_);");
         arguments.add("'uri3': uri3_");
         break;
 
       case "count":
         parameters.add("int count");
-        conversions.add("if (count == null) throw 'No count provided';");
+        conversions.add(
+            "$ignoreNotNull\n" "if (count == null) throw 'No count provided';");
         arguments.add("'count': count");
         break;
 
       case "count2":
         parameters.add("int count2");
-        conversions.add("if (count2 == null) throw 'No count provided';");
+        conversions.add("$ignoreNotNull\n"
+            "if (count2 == null) throw 'No count provided';");
         arguments.add("'count2': count2");
         break;
 
@@ -354,21 +359,24 @@
 
       case "num1":
         parameters.add("num _num1");
-        conversions.add("if (_num1 == null) throw 'No number provided';");
+        conversions.add("$ignoreNotNull\n"
+            "if (_num1 == null) throw 'No number provided';");
         conversions.add("String num1 = ${format('_num1')};");
         arguments.add("'num1': _num1");
         break;
 
       case "num2":
         parameters.add("num _num2");
-        conversions.add("if (_num2 == null) throw 'No number provided';");
+        conversions.add("$ignoreNotNull\n"
+            "if (_num2 == null) throw 'No number provided';");
         conversions.add("String num2 = ${format('_num2')};");
         arguments.add("'num2': _num2");
         break;
 
       case "num3":
         parameters.add("num _num3");
-        conversions.add("if (_num3 == null) throw 'No number provided';");
+        conversions.add("$ignoreNotNull\n"
+            "if (_num3 == null) throw 'No number provided';");
         conversions.add("String num3 = ${format('_num3')};");
         arguments.add("'num3': _num3");
         break;
@@ -459,7 +467,7 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(${parameters.join(', ')})> code$name =
     const Code<Message Function(${parameters.join(', ')})>(
-        \"$name\", template$name, ${codeArguments.join(', ')});
+        \"$name\", ${codeArguments.join(', ')});
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArguments$name(${parameters.join(', ')}) {
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index a93760a..2bfc380 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -147,7 +147,7 @@
 
 type ComponentFile {
   UInt32 magic = 0x90ABCDEF;
-  UInt32 formatVersion = 52;
+  UInt32 formatVersion = 53;
   Byte[10] shortSdkHash;
   List<String> problemsAsJson; // Described in problems.md.
   Library[] libraries;
@@ -615,12 +615,86 @@
   MemberReference interfaceTargetOrigin; // May be NullReference.
 }
 
+/*
+enum InstanceAccessKind {
+  Instance,
+  Object,
+  Inapplicable,
+  Nullable,
+}
+*/
+
+type InstanceGet extends Expression {
+  Byte tag = 118;
+  Byte kind; // Index into InstanceAccessKind above.
+  FileOffset fileOffset;
+  Expression receiver;
+  Name name;
+  DartType resultType;
+  MemberReference interfaceTarget;
+  MemberReference interfaceTargetOrigin; // May be NullReference.
+}
+
+type InstanceSet extends Expression {
+  Byte tag = 119;
+  Byte kind; // Index into InstanceAccessKind above.
+  FileOffset fileOffset;
+  Expression receiver;
+  Name name;
+  Expression value;
+  MemberReference interfaceTarget;
+  MemberReference interfaceTargetOrigin; // May be NullReference.
+}
+
+type InstanceTearOff extends Expression {
+  Byte tag = 121;
+  Byte kind; // Index into InstanceAccessKind above.
+  FileOffset fileOffset;
+  Expression receiver;
+  Name name;
+  DartType resultType;
+  MemberReference interfaceTarget;
+  MemberReference interfaceTargetOrigin; // May be NullReference.
+}
+
+/*
+enum DynamicAccessKind {
+  Dynamic,
+  Never,
+  Invalid,
+  Unresolved,
+}
+*/
+
+type DynamicGet extends Expression {
+  Byte tag = 122;
+  Byte kind; // Index into DynamicAccessKind above.
+  FileOffset fileOffset;
+  Expression receiver;
+  Name name;
+}
+
+type DynamicSet extends Expression {
+  Byte tag = 123;
+  Byte kind; // Index into DynamicAccessKind above.
+  FileOffset fileOffset;
+  Expression receiver;
+  Name name;
+  Expression value;
+}
+
 type StaticGet extends Expression {
   Byte tag = 26;
   FileOffset fileOffset;
   MemberReference target;
 }
 
+type StaticTearOff extends Expression {
+  Byte tag = 17;
+  FileOffset fileOffset;
+  MemberReference target;
+}
+
 type StaticSet extends Expression {
   Byte tag = 27;
   FileOffset fileOffset;
@@ -644,7 +718,7 @@
 
 type MethodInvocation extends Expression {
   Byte tag = 28;
-  Byte flags;
+  Byte flags (isInvariant, isBoundsSafe);
   FileOffset fileOffset;
   Expression receiver;
   Name name;
@@ -653,6 +727,81 @@
   MemberReference interfaceTargetOrigin; // May be NullReference.
 }
 
+type InstanceInvocation extends Expression {
+  Byte tag = 120;
+  Byte kind; // Index into InstanceAccessKind above.
+  Byte flags (isInvariant, isBoundsSafe);
+  FileOffset fileOffset;
+  Expression receiver;
+  Name name;
+  Arguments arguments;
+  DartType functionType;
+  MemberReference interfaceTarget;
+  MemberReference interfaceTargetOrigin; // May be NullReference.
+}
+
+type DynamicInvocation extends Expression {
+  Byte tag = 124;
+  Byte kind; // Index into DynamicAccessKind above.
+  FileOffset fileOffset;
+  Expression receiver;
+  Name name;
+  Arguments arguments;
+}
+
+/*
+enum FunctionAccessKind {
+  Function,
+  FunctionType,
+  Inapplicable,
+  Nullable,
+}
+*/
+
+type FunctionInvocation extends Expression {
+  Byte tag = 125;
+  Byte kind; // Index into FunctionAccessKind above.
+  FileOffset fileOffset;
+  Expression receiver;
+  Arguments arguments;
+  DartType functionType; // Use `const DynamicType()` as `null`.
+}
+
+type FunctionTearOff extends Expression {
+  Byte tag = 126;
+  FileOffset fileOffset;
+  Expression receiver;
+  DartType functionType;
+}
+
+type LocalFunctionInvocation extends Expression {
+  Byte tag = 127;
+  FileOffset fileOffset;
+  // Byte offset in the binary for the variable declaration (without tag).
+  UInt variableDeclarationPosition;
+  VariableReference variable;
+  Arguments arguments;
+  DartType functionType;
+}
+
+type EqualsNull extends Expression {
+  Byte tag = 15;
+  FileOffset fileOffset;
+  Expression expression;
+  Byte isNot;
+}
+
+type EqualsCall extends Expression {
+  Byte tag = 16;
+  FileOffset fileOffset;
+  Expression left;
+  Expression right;
+  Byte isNot;
+  DartType functionType;
+  MemberReference interfaceTarget;
+  MemberReference interfaceTargetOrigin; // May be NullReference.
+}
+
 type SuperMethodInvocation extends Expression {
   Byte tag = 29;
   FileOffset fileOffset;
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 41c88aa..f80d63f 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -3414,6 +3414,280 @@
   }
 }
 
+enum DynamicAccessKind {
+  /// An access on a receiver of type dynamic.
+  ///
+  /// An access of this kind always results in a value of static type dynamic.
+  ///
+  /// Valid accesses to Object members on receivers of type dynamic are encoded
+  /// as an [InstanceInvocation] of kind [InstanceAccessKind.Object].
+  Dynamic,
+
+  /// An access on a receiver of type Never.
+  ///
+  /// An access of this kind always results in a value of static type Never.
+  ///
+  /// Valid accesses to Object members on receivers of type Never are also
+  /// encoded as [DynamicInvocation] of kind [DynamicAccessKind.Never] and _not_
+  /// as an [InstanceInvocation] of kind [InstanceAccessKind.Object].
+  Never,
+
+  /// An access on a receiver of an invalid type.
+  ///
+  /// An access of this kind always results in a value of an invalid static
+  /// type.
+  Invalid,
+
+  Unresolved,
+}
+
+class DynamicGet extends Expression {
+  final DynamicAccessKind kind;
+  Expression receiver;
+  Name name;
+
+  DynamicGet(this.kind, this.receiver, this.name) {
+    receiver?.parent = this;
+  }
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicGet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitDynamicGet(this, arg);
+
+  @override
+  DartType getStaticTypeInternal(StaticTypeContext context) {
+    switch (kind) {
+      case DynamicAccessKind.Dynamic:
+        return const DynamicType();
+      case DynamicAccessKind.Never:
+        return const NeverType(Nullability.nonNullable);
+      case DynamicAccessKind.Invalid:
+      case DynamicAccessKind.Unresolved:
+        return const InvalidType();
+    }
+    return const DynamicType();
+  }
+
+  @override
+  void visitChildren(Visitor v) {
+    receiver?.accept(v);
+    name?.accept(v);
+  }
+
+  @override
+  void transformChildren(Transformer v) {
+    if (receiver != null) {
+      receiver = receiver.accept<TreeNode>(v);
+      receiver?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "DynamicGet($kind,${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver,
+        minimumPrecedence: astToText.Precedence.PRIMARY);
+    printer.write('.');
+    printer.writeName(name);
+  }
+}
+
+/// An property read of an instance getter or field with a statically known
+/// interface target.
+class InstanceGet extends Expression {
+  final InstanceAccessKind kind;
+  Expression receiver;
+  Name name;
+
+  /// The static type of result of the property read.
+  ///
+  /// This includes substituted type parameters from the static receiver type.
+  ///
+  /// For instance
+  ///
+  ///    class A<T> {
+  ///      T get t;
+  ///    }
+  ///    m(A<String> a) {
+  ///      a.t; // The result type is `String`.
+  ///    }
+  ///
+  DartType resultType;
+
+  Reference interfaceTargetReference;
+
+  InstanceGet(InstanceAccessKind kind, Expression receiver, Name name,
+      {Member interfaceTarget, DartType resultType})
+      : this.byReference(kind, receiver, name,
+            interfaceTargetReference: getMemberReferenceGetter(interfaceTarget),
+            resultType: resultType);
+
+  InstanceGet.byReference(this.kind, this.receiver, this.name,
+      {this.interfaceTargetReference, this.resultType})
+      : assert(interfaceTargetReference != null),
+        assert(resultType != null) {
+    receiver?.parent = this;
+  }
+
+  Member get interfaceTarget => interfaceTargetReference?.asMember;
+
+  void set interfaceTarget(Member member) {
+    interfaceTargetReference = getMemberReferenceSetter(member);
+  }
+
+  @override
+  DartType getStaticTypeInternal(StaticTypeContext context) => resultType;
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceGet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitInstanceGet(this, arg);
+
+  visitChildren(Visitor v) {
+    receiver?.accept(v);
+    interfaceTarget?.acceptReference(v);
+    name?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (receiver != null) {
+      receiver = receiver.accept<TreeNode>(v);
+      receiver?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "InstanceGet($kind,${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver,
+        minimumPrecedence: astToText.Precedence.PRIMARY);
+    printer.write('.');
+    printer.writeInterfaceMemberName(interfaceTargetReference, name);
+  }
+}
+
+/// A tear-off of the 'call' method on an expression whose static type is
+/// a function type or the type 'Function'.
+class FunctionTearOff extends Expression {
+  Expression receiver;
+
+  FunctionTearOff(this.receiver) {
+    receiver?.parent = this;
+  }
+
+  DartType getStaticTypeInternal(StaticTypeContext context) =>
+      receiver.getStaticType(context);
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionTearOff(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitFunctionTearOff(this, arg);
+
+  visitChildren(Visitor v) {
+    receiver?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (receiver != null) {
+      receiver = receiver.accept<TreeNode>(v);
+      receiver?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "FunctionTearOff(${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver,
+        minimumPrecedence: astToText.Precedence.PRIMARY);
+    printer.write('.');
+    printer.writeName(Name.callName);
+  }
+}
+
+/// A tear-off of an instance method with a statically known interface target.
+class InstanceTearOff extends Expression {
+  final InstanceAccessKind kind;
+  Expression receiver;
+  Name name;
+
+  /// The static type of result of the tear-off.
+  ///
+  /// This includes substituted type parameters from the static receiver type.
+  ///
+  /// For instance
+  ///
+  ///    class A<T, S> {
+  ///      T method<U>(S s, U u) { ... }
+  ///    }
+  ///    m(A<String, int> a) {
+  ///      a.method; // The result type is `String Function<U>(int, U)`.
+  ///    }
+  ///
+  DartType resultType;
+
+  Reference interfaceTargetReference;
+
+  InstanceTearOff(InstanceAccessKind kind, Expression receiver, Name name,
+      {Procedure interfaceTarget, DartType resultType})
+      : this.byReference(kind, receiver, name,
+            interfaceTargetReference: getMemberReferenceGetter(interfaceTarget),
+            resultType: resultType);
+
+  InstanceTearOff.byReference(this.kind, this.receiver, this.name,
+      {this.interfaceTargetReference, this.resultType}) {
+    receiver?.parent = this;
+  }
+
+  Procedure get interfaceTarget => interfaceTargetReference?.asMember;
+
+  void set interfaceTarget(Member member) {
+    interfaceTargetReference = getMemberReferenceSetter(member);
+  }
+
+  @override
+  DartType getStaticTypeInternal(StaticTypeContext context) => resultType;
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceTearOff(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitInstanceTearOff(this, arg);
+
+  visitChildren(Visitor v) {
+    receiver?.accept(v);
+    interfaceTarget?.acceptReference(v);
+    name?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (receiver != null) {
+      receiver = receiver.accept<TreeNode>(v);
+      receiver?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "InstanceTearOff($kind, ${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver,
+        minimumPrecedence: astToText.Precedence.PRIMARY);
+    printer.write('.');
+    printer.writeInterfaceMemberName(interfaceTargetReference, name);
+  }
+}
+
 /// Expression of form `x.field`.
 ///
 /// This may invoke a getter, read a field, or tear off a method.
@@ -3438,7 +3712,6 @@
     interfaceTargetReference = getMemberReferenceGetter(member);
   }
 
-  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
     Member interfaceTarget = this.interfaceTarget;
     if (interfaceTarget != null) {
@@ -3489,6 +3762,128 @@
   }
 }
 
+class DynamicSet extends Expression {
+  final DynamicAccessKind kind;
+  Expression receiver;
+  Name name;
+  Expression value;
+
+  DynamicSet(this.kind, this.receiver, this.name, this.value) {
+    receiver?.parent = this;
+    value?.parent = this;
+  }
+
+  DartType getStaticTypeInternal(StaticTypeContext context) =>
+      value.getStaticType(context);
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicSet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitDynamicSet(this, arg);
+
+  visitChildren(Visitor v) {
+    receiver?.accept(v);
+    name?.accept(v);
+    value?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (receiver != null) {
+      receiver = receiver.accept<TreeNode>(v);
+      receiver?.parent = this;
+    }
+    if (value != null) {
+      value = value.accept<TreeNode>(v);
+      value?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "DynamicSet($kind,${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver,
+        minimumPrecedence: astToText.Precedence.PRIMARY);
+    printer.write('.');
+    printer.writeName(name);
+    printer.write(' = ');
+    printer.writeExpression(value);
+  }
+}
+
+/// An property write of an instance setter or field with a statically known
+/// interface target.
+class InstanceSet extends Expression {
+  final InstanceAccessKind kind;
+  Expression receiver;
+  Name name;
+  Expression value;
+
+  Reference interfaceTargetReference;
+
+  InstanceSet(
+      InstanceAccessKind kind, Expression receiver, Name name, Expression value,
+      {Member interfaceTarget})
+      : this.byReference(kind, receiver, name, value,
+            interfaceTargetReference:
+                getMemberReferenceSetter(interfaceTarget));
+
+  InstanceSet.byReference(this.kind, this.receiver, this.name, this.value,
+      {this.interfaceTargetReference})
+      : assert(interfaceTargetReference != null) {
+    receiver?.parent = this;
+    value?.parent = this;
+  }
+
+  Member get interfaceTarget => interfaceTargetReference?.asMember;
+
+  void set interfaceTarget(Member member) {
+    interfaceTargetReference = getMemberReferenceSetter(member);
+  }
+
+  DartType getStaticTypeInternal(StaticTypeContext context) =>
+      value.getStaticType(context);
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceSet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitInstanceSet(this, arg);
+
+  visitChildren(Visitor v) {
+    receiver?.accept(v);
+    interfaceTarget?.acceptReference(v);
+    name?.accept(v);
+    value?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (receiver != null) {
+      receiver = receiver.accept<TreeNode>(v);
+      receiver?.parent = this;
+    }
+    if (value != null) {
+      value = value.accept<TreeNode>(v);
+      value?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "InstanceSet(${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver,
+        minimumPrecedence: astToText.Precedence.PRIMARY);
+    printer.write('.');
+    printer.writeInterfaceMemberName(interfaceTargetReference, name);
+    printer.write(' = ');
+    printer.writeExpression(value);
+  }
+}
+
 /// Expression of form `x.field = value`.
 ///
 /// This may invoke a setter or assign a field.
@@ -3518,10 +3913,6 @@
     interfaceTargetReference = getMemberReferenceSetter(member);
   }
 
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       value.getStaticType(context);
 
@@ -3648,10 +4039,6 @@
     interfaceTargetReference = getMemberReferenceSetter(member);
   }
 
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       value.getStaticType(context);
 
@@ -3701,10 +4088,6 @@
     targetReference = getMemberReferenceGetter(target);
   }
 
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       target.getterType;
 
@@ -3729,6 +4112,45 @@
   }
 }
 
+/// Tear-off of a static method.
+class StaticTearOff extends Expression {
+  Reference targetReference;
+
+  StaticTearOff(Procedure target)
+      : this.byReference(getMemberReferenceGetter(target));
+
+  StaticTearOff.byReference(this.targetReference);
+
+  Procedure get target => targetReference?.asProcedure;
+
+  void set target(Procedure target) {
+    targetReference = getMemberReferenceGetter(target);
+  }
+
+  DartType getStaticTypeInternal(StaticTypeContext context) =>
+      target.getterType;
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticTearOff(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitStaticTearOff(this, arg);
+
+  visitChildren(Visitor v) {
+    target?.acceptReference(v);
+  }
+
+  transformChildren(Transformer v) {}
+
+  @override
+  String toString() {
+    return "StaticTearOff(${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeMemberName(targetReference);
+  }
+}
+
 /// Assign a static field or call a static setter.
 ///
 /// Evaluates to the value of [value].
@@ -3750,10 +4172,6 @@
     targetReference = getMemberReferenceSetter(target);
   }
 
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       value.getStaticType(context);
 
@@ -3916,7 +4334,7 @@
 /// [SuperMethodInvocation], [StaticInvocation], and [ConstructorInvocation].
 abstract class InvocationExpression extends Expression {
   Arguments get arguments;
-  set arguments(Arguments value);
+  void set arguments(Arguments value);
 
   /// Name of the invoked method.
   ///
@@ -3924,6 +4342,566 @@
   Name get name;
 }
 
+class DynamicInvocation extends InvocationExpression {
+  final DynamicAccessKind kind;
+  Expression receiver;
+  Name name;
+  Arguments arguments;
+
+  DynamicInvocation(this.kind, this.receiver, this.name, this.arguments) {
+    receiver?.parent = this;
+    arguments?.parent = this;
+  }
+
+  @override
+  DartType getStaticTypeInternal(StaticTypeContext context) {
+    switch (kind) {
+      case DynamicAccessKind.Dynamic:
+        return const DynamicType();
+      case DynamicAccessKind.Never:
+        return const NeverType(Nullability.nonNullable);
+      case DynamicAccessKind.Invalid:
+      case DynamicAccessKind.Unresolved:
+        return const InvalidType();
+    }
+    return const DynamicType();
+  }
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicInvocation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitDynamicInvocation(this, arg);
+
+  visitChildren(Visitor v) {
+    receiver?.accept(v);
+    name?.accept(v);
+    arguments?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (receiver != null) {
+      receiver = receiver.accept<TreeNode>(v);
+      receiver?.parent = this;
+    }
+    if (arguments != null) {
+      arguments = arguments.accept<TreeNode>(v);
+      arguments?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "DynamicInvocation($kind,${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver,
+        minimumPrecedence: astToText.Precedence.PRIMARY);
+    printer.write('.');
+    printer.writeName(name);
+    printer.writeArguments(arguments);
+  }
+}
+
+/// Access kind used by [InstanceInvocation], [InstanceGet], [InstanceSet],
+/// and [InstanceTearOff].
+enum InstanceAccessKind {
+  /// An access to a member on a static receiver type which is an interface
+  /// type.
+  ///
+  /// In null safe libraries the static receiver type is non-nullable.
+  ///
+  /// For instance:
+  ///
+  ///     class C { void method() {} }
+  ///     main() => new C().method();
+  ///
+  Instance,
+
+  /// An access to a member defined on Object on a static receiver type that
+  /// is either a non-interface type or a nullable type.
+  ///
+  /// For instance:
+  ///
+  ///     test1(String? s) => s.toString();
+  ///     test1(dynamic s) => s.hashCode;
+  ///
+  Object,
+
+  /// An access to a method on a static receiver type which is an interface
+  /// type which is inapplicable, that is, whose arguments don't match the
+  /// required parameter structure.
+  ///
+  /// This is an error case which is only used on expression nested within
+  /// [InvalidExpression]s.
+  ///
+  /// For instance:
+  ///
+  ///     class C { void method() {} }
+  ///     main() => new C().method(0); // Too many arguments.
+  ///
+  Inapplicable,
+
+  /// An access to a non-Object member on a static receiver type which is a
+  /// nullable interface type.
+  ///
+  /// This is an error case which is only used on expression nested within
+  /// [InvalidExpression]s.
+  ///
+  /// For instance:
+  ///
+  ///     class C { void method() {} }
+  ///     test(C? c) => c.method(0); // 'c' is nullable.
+  ///
+  Nullable,
+}
+
+/// An invocation of an instance method with a statically known interface
+/// target.
+class InstanceInvocation extends InvocationExpression {
+  // Must match serialized bit positions.
+  static const int FlagInvariant = 1 << 0;
+  static const int FlagBoundsSafe = 1 << 1;
+
+  final InstanceAccessKind kind;
+  Expression receiver;
+  Name name;
+  Arguments arguments;
+  int flags = 0;
+
+  /// The static type of the invocation.
+  ///
+  /// This includes substituted type parameters from the static receiver type
+  /// and generic type arguments.
+  ///
+  /// For instance
+  ///
+  ///    class A<T> {
+  ///      Map<T, S> map<S>(S s) { ... }
+  ///    }
+  ///    m(A<String> a) {
+  ///      a.map(0); // The function type is `Map<String, int> Function(int)`.
+  ///    }
+  ///
+  FunctionType functionType;
+
+  Reference interfaceTargetReference;
+
+  InstanceInvocation(InstanceAccessKind kind, Expression receiver, Name name,
+      Arguments arguments, {Member interfaceTarget, FunctionType functionType})
+      : this.byReference(kind, receiver, name, arguments,
+            interfaceTargetReference: getMemberReferenceGetter(interfaceTarget),
+            functionType: functionType);
+
+  InstanceInvocation.byReference(
+      this.kind, this.receiver, this.name, this.arguments,
+      {this.interfaceTargetReference, this.functionType})
+      : assert(interfaceTargetReference != null),
+        assert(functionType != null),
+        assert(functionType.typeParameters.isEmpty) {
+    receiver?.parent = this;
+    arguments?.parent = this;
+  }
+
+  Member get interfaceTarget => interfaceTargetReference?.asMember;
+
+  void set interfaceTarget(Member target) {
+    interfaceTargetReference = getMemberReferenceGetter(target);
+  }
+
+  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
+  ///
+  /// This is for instance the case in code patterns like this
+  ///
+  ///     List<int> list = <int>[];
+  ///     list.add(0);
+  ///
+  /// where the `list` variable is known to hold a value of the same type as
+  /// the static type. In contrast the would not be the case in code patterns
+  /// like this
+  ///
+  ///     List<num> list = <double>[];
+  ///     list.add(0); // Runtime error `int` is not a subtype of `double`.
+  ///
+  bool get isInvariant => flags & FlagInvariant != 0;
+
+  void set isInvariant(bool value) {
+    flags = value ? (flags | FlagInvariant) : (flags & ~FlagInvariant);
+  }
+
+  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
+  ///
+  /// This is for instance the case in code patterns like this
+  ///
+  ///     List list = new List.filled(2, 0);
+  ///     list[1] = 42;
+  ///
+  /// where the `list` is known to have a sufficient length for the update
+  /// in `list[1] = 42`.
+  bool get isBoundsSafe => flags & FlagBoundsSafe != 0;
+
+  void set isBoundsSafe(bool value) {
+    flags = value ? (flags | FlagBoundsSafe) : (flags & ~FlagBoundsSafe);
+  }
+
+  DartType getStaticTypeInternal(StaticTypeContext context) =>
+      functionType.returnType;
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceInvocation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitInstanceInvocation(this, arg);
+
+  visitChildren(Visitor v) {
+    receiver?.accept(v);
+    interfaceTarget?.acceptReference(v);
+    name?.accept(v);
+    arguments?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (receiver != null) {
+      receiver = receiver.accept<TreeNode>(v);
+      receiver?.parent = this;
+    }
+    if (arguments != null) {
+      arguments = arguments.accept<TreeNode>(v);
+      arguments?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "InstanceInvocation($kind, ${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver,
+        minimumPrecedence: astToText.Precedence.PRIMARY);
+    printer.write('.');
+    printer.writeInterfaceMemberName(interfaceTargetReference, name);
+    printer.writeArguments(arguments);
+  }
+}
+
+/// Access kind used by [FunctionInvocation] and [FunctionTearOff].
+enum FunctionAccessKind {
+  /// An access to the 'call' method on an expression of static type `Function`.
+  ///
+  /// For instance
+  ///
+  ///     method(Function f) => f();
+  ///
+  Function,
+
+  /// An access to the 'call' method on an expression whose static type is a
+  /// function type.
+  ///
+  /// For instance
+  ///
+  ///     method(void Function() f) => f();
+  ///
+  FunctionType,
+
+  /// An access to the 'call' method on an expression whose static type is a
+  /// function type which is inapplicable, that is, whose arguments don't match
+  /// the required parameter structure.
+  ///
+  /// This is an error case which is only used on expression nested within
+  /// [InvalidExpression]s.
+  ///
+  /// For instance:
+  ///
+  ///     test(void Function() f) => f(0); // Too many arguments.
+  ///
+  Inapplicable,
+
+  /// An access to the 'call' method on an expression whose static type is a
+  /// nullable function type or `Function?`.
+  ///
+  /// This is an error case which is only used on expression nested within
+  /// [InvalidExpression]s.
+  ///
+  /// For instance:
+  ///
+  ///     test(void Function()? f) => f(); // 'f' is nullable.
+  ///
+  Nullable,
+}
+
+/// An invocation of the 'call' method on an expression whose static type is
+/// a function type or the type 'Function'.
+class FunctionInvocation extends InvocationExpression {
+  final FunctionAccessKind kind;
+
+  Expression receiver;
+
+  Arguments arguments;
+
+  /// The static type of the invocation.
+  ///
+  /// This is `null` if the static type of the receiver is not a function type
+  /// or is not bounded by a function type.
+  ///
+  /// For instance
+  ///
+  ///    m<T extends Function, S extends int Function()>(T t, S s, Function f) {
+  ///      X local<X>(X t) => t;
+  ///      t(); // The function type is `null`.
+  ///      s(); // The function type is `int Function()`.
+  ///      f(); // The function type is `null`.
+  ///      local(0); // The function type is `int Function(int)`.
+  ///    }
+  ///
+  FunctionType functionType;
+
+  FunctionInvocation(this.kind, this.receiver, this.arguments,
+      {this.functionType}) {
+    receiver?.parent = this;
+    arguments?.parent = this;
+  }
+
+  Name get name => Name.callName;
+
+  DartType getStaticTypeInternal(StaticTypeContext context) =>
+      functionType?.returnType ?? const DynamicType();
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionInvocation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitFunctionInvocation(this, arg);
+
+  visitChildren(Visitor v) {
+    receiver?.accept(v);
+    name?.accept(v);
+    arguments?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (receiver != null) {
+      receiver = receiver.accept<TreeNode>(v);
+      receiver?.parent = this;
+    }
+    if (arguments != null) {
+      arguments = arguments.accept<TreeNode>(v);
+      arguments?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "FunctionInvocation(${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(receiver,
+        minimumPrecedence: astToText.Precedence.PRIMARY);
+    printer.writeArguments(arguments);
+  }
+}
+
+/// An invocation of a local function declaration.
+class LocalFunctionInvocation extends InvocationExpression {
+  /// The variable declaration for the function declaration.
+  VariableDeclaration variable;
+  Arguments arguments;
+
+  /// The static type of the invocation.
+  ///
+  /// This might differ from the static type of [variable] for generic
+  /// functions.
+  ///
+  /// For instance
+  ///
+  ///    m() {
+  ///      T local<T>(T t) => t;
+  ///      local(0); // The static type is `int Function(int)`.
+  ///    }
+  ///
+  FunctionType functionType;
+
+  LocalFunctionInvocation(this.variable, this.arguments, {this.functionType})
+      : assert(functionType != null) {
+    arguments?.parent = this;
+  }
+
+  Name get name => Name.callName;
+
+  @override
+  DartType getStaticTypeInternal(StaticTypeContext context) =>
+      functionType.returnType;
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitLocalFunctionInvocation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitLocalFunctionInvocation(this, arg);
+
+  visitChildren(Visitor v) {
+    arguments?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (arguments != null) {
+      arguments = arguments.accept<TreeNode>(v);
+      arguments?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "LocalFunctionInvocation(${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.write(printer.getVariableName(variable));
+    printer.writeArguments(arguments);
+  }
+}
+
+/// Nullness test of an expression, that is `e == null` or `e != null`.
+///
+/// This is generated for code like `e1 == e2` and `e1 != e2` where `e1` or `e2`
+/// is `null`.
+class EqualsNull extends Expression {
+  /// The expression tested for nullness.
+  Expression expression;
+
+  /// If `true` this is an `e != null` test. Otherwise it is an `e == null`
+  /// test.
+  final bool isNot;
+
+  EqualsNull(this.expression, {this.isNot}) : assert(isNot != null) {
+    expression?.parent = this;
+  }
+
+  @override
+  DartType getStaticTypeInternal(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitEqualsNull(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitEqualsNull(this, arg);
+
+  visitChildren(Visitor v) {
+    expression?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (expression != null) {
+      expression = expression.accept<TreeNode>(v);
+      expression?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "EqualsNull(${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeExpression(expression, minimumPrecedence: precedence);
+    if (isNot) {
+      printer.write(' != null');
+    } else {
+      printer.write(' == null');
+    }
+  }
+}
+
+/// A test of equality, that is `e1 == e2` or `e1 != e2`.
+///
+/// This is generated for code like `e1 == e2` and `e1 != e2` where neither `e1`
+/// nor `e2` is `null`.
+class EqualsCall extends Expression {
+  Expression left;
+  Expression right;
+
+  /// The static type of the invocation.
+  ///
+  /// This might differ from the static type of [Object.==] for covariant
+  /// parameters.
+  ///
+  /// For instance
+  ///
+  ///    class C<T> {
+  ///      bool operator(covariant C<T> other) { ... }
+  ///    }
+  ///    // The function type is `bool Function(C<num>)`.
+  ///    method(C<num> a, C<int> b) => a == b;
+  ///
+  FunctionType functionType;
+
+  /// If `true` this is an `e1 != e2` test. Otherwise it is an `e1 == e2` test.
+  final bool isNot;
+
+  Reference interfaceTargetReference;
+
+  EqualsCall(Expression left, Expression right,
+      {bool isNot, FunctionType functionType, Procedure interfaceTarget})
+      : this.byReference(left, right,
+            isNot: isNot,
+            functionType: functionType,
+            interfaceTargetReference:
+                getMemberReferenceGetter(interfaceTarget));
+
+  EqualsCall.byReference(this.left, this.right,
+      {this.isNot, this.functionType, this.interfaceTargetReference})
+      : assert(isNot != null) {
+    left?.parent = this;
+    right?.parent = this;
+  }
+
+  Procedure get interfaceTarget => interfaceTargetReference?.asProcedure;
+
+  void set interfaceTarget(Procedure target) {
+    interfaceTargetReference = getMemberReferenceGetter(target);
+  }
+
+  DartType getStaticTypeInternal(StaticTypeContext context) {
+    return functionType?.returnType ??
+        context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
+  }
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitEqualsCall(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitEqualsCall(this, arg);
+
+  visitChildren(Visitor v) {
+    left?.accept(v);
+    interfaceTarget?.acceptReference(v);
+    right?.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    if (left != null) {
+      left = left.accept<TreeNode>(v);
+      left?.parent = this;
+    }
+    if (right != null) {
+      right = right.accept<TreeNode>(v);
+      right?.parent = this;
+    }
+  }
+
+  @override
+  String toString() {
+    return "EqualsCall(${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    int minimumPrecedence = precedence;
+    printer.writeExpression(left, minimumPrecedence: minimumPrecedence);
+    if (isNot) {
+      printer.write(' != ');
+    } else {
+      printer.write(' == ');
+    }
+    printer.writeExpression(right, minimumPrecedence: minimumPrecedence + 1);
+  }
+}
+
 /// Expression of form `x.foo(y)`.
 class MethodInvocation extends InvocationExpression {
   // Must match serialized bit positions.
@@ -7429,6 +8407,12 @@
   void toTextInternal(AstPrinter printer) {
     printer.writeName(this);
   }
+
+  /// The name of the `call` method on a function.
+  static final Name callName = new _PublicName('call');
+
+  /// The name of the `==` operator.
+  static final Name equalsName = new _PublicName('==');
 }
 
 class _PrivateName extends Name {
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 4a94b88..5d9ca40 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -1672,7 +1672,8 @@
   VariableDeclaration readVariableReference() {
     int index = readUInt30();
     if (index >= variableStack.length) {
-      throw fail('unexpected variable index: $index');
+      throw fail('Unexpected variable index: $index. '
+          'Current variable count: ${variableStack.length}.');
     }
     return variableStack[index];
   }
@@ -1742,11 +1743,44 @@
         return new PropertyGet.byReference(readExpression(), readName(),
             readInstanceMemberReference(allowNull: true))
           ..fileOffset = offset;
+      case Tag.InstanceGet:
+        InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
+        int offset = readOffset();
+        return new InstanceGet.byReference(kind, readExpression(), readName(),
+            resultType: readDartType(),
+            interfaceTargetReference: readInstanceMemberReference())
+          ..fileOffset = offset;
+      case Tag.InstanceTearOff:
+        InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
+        int offset = readOffset();
+        return new InstanceTearOff.byReference(
+            kind, readExpression(), readName(),
+            resultType: readDartType(),
+            interfaceTargetReference: readInstanceMemberReference())
+          ..fileOffset = offset;
+      case Tag.DynamicGet:
+        DynamicAccessKind kind = DynamicAccessKind.values[readByte()];
+        int offset = readOffset();
+        return new DynamicGet(kind, readExpression(), readName())
+          ..fileOffset = offset;
       case Tag.PropertySet:
         int offset = readOffset();
         return new PropertySet.byReference(readExpression(), readName(),
             readExpression(), readInstanceMemberReference(allowNull: true))
           ..fileOffset = offset;
+      case Tag.InstanceSet:
+        InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
+        int offset = readOffset();
+        return new InstanceSet.byReference(
+            kind, readExpression(), readName(), readExpression(),
+            interfaceTargetReference: readInstanceMemberReference())
+          ..fileOffset = offset;
+      case Tag.DynamicSet:
+        DynamicAccessKind kind = DynamicAccessKind.values[readByte()];
+        int offset = readOffset();
+        return new DynamicSet(
+            kind, readExpression(), readName(), readExpression())
+          ..fileOffset = offset;
       case Tag.SuperPropertyGet:
         int offset = readOffset();
         addTransformerFlag(TransformerFlag.superCalls);
@@ -1763,6 +1797,10 @@
         int offset = readOffset();
         return new StaticGet.byReference(readMemberReference())
           ..fileOffset = offset;
+      case Tag.StaticTearOff:
+        int offset = readOffset();
+        return new StaticTearOff.byReference(readMemberReference())
+          ..fileOffset = offset;
       case Tag.StaticSet:
         int offset = readOffset();
         return new StaticSet.byReference(
@@ -1775,6 +1813,55 @@
             readArguments(), readInstanceMemberReference(allowNull: true))
           ..fileOffset = offset
           ..flags = flags;
+      case Tag.InstanceInvocation:
+        InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
+        int flags = readByte();
+        int offset = readOffset();
+        return new InstanceInvocation.byReference(
+            kind, readExpression(), readName(), readArguments(),
+            functionType: readDartType(),
+            interfaceTargetReference: readInstanceMemberReference())
+          ..fileOffset = offset
+          ..flags = flags;
+      case Tag.DynamicInvocation:
+        DynamicAccessKind kind = DynamicAccessKind.values[readByte()];
+        int offset = readOffset();
+        return new DynamicInvocation(
+            kind, readExpression(), readName(), readArguments())
+          ..fileOffset = offset;
+      case Tag.FunctionInvocation:
+        FunctionAccessKind kind = FunctionAccessKind.values[readByte()];
+        int offset = readOffset();
+        Expression receiver = readExpression();
+        Arguments arguments = readArguments();
+        DartType functionType = readDartType();
+        // `const DynamicType()` is used to encode a missing function type.
+        assert(functionType is FunctionType || functionType is DynamicType,
+            "Unexpected function type $functionType for FunctionInvocation");
+        return new FunctionInvocation(kind, receiver, arguments,
+            functionType: functionType is FunctionType ? functionType : null)
+          ..fileOffset = offset;
+      case Tag.FunctionTearOff:
+        int offset = readOffset();
+        return new FunctionTearOff(readExpression())..fileOffset = offset;
+      case Tag.LocalFunctionInvocation:
+        int offset = readOffset();
+        readUInt30(); // offset of the variable declaration in the binary.
+        return new LocalFunctionInvocation(
+            readVariableReference(), readArguments(),
+            functionType: readDartType())
+          ..fileOffset = offset;
+      case Tag.EqualsNull:
+        int offset = readOffset();
+        return new EqualsNull(readExpression(), isNot: readByte() == 1)
+          ..fileOffset = offset;
+      case Tag.EqualsCall:
+        int offset = readOffset();
+        return new EqualsCall.byReference(readExpression(), readExpression(),
+            isNot: readByte() == 1,
+            functionType: readDartType(),
+            interfaceTargetReference: readInstanceMemberReference())
+          ..fileOffset = offset;
       case Tag.SuperMethodInvocation:
         int offset = readOffset();
         addTransformerFlag(TransformerFlag.superCalls);
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index ca92ca9..6c09178 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -80,6 +80,13 @@
     _sink.flushAndDestroy();
   }
 
+  int _getVariableIndex(VariableDeclaration variable) {
+    _variableIndexer ??= new VariableIndexer();
+    int index = _variableIndexer[variable];
+    assert(index != null, "No index found for ${variable}");
+    return index;
+  }
+
   void writeByte(int byte) {
     assert((byte & 0xFF) == byte);
     _sink.addByte(byte);
@@ -1383,9 +1390,7 @@
 
   @override
   void visitVariableGet(VariableGet node) {
-    _variableIndexer ??= new VariableIndexer();
-    int index = _variableIndexer[node.variable];
-    assert(index != null, "No index found for ${node.variable}");
+    int index = _getVariableIndex(node.variable);
     if (index & Tag.SpecializedPayloadMask == index &&
         node.promotedType == null) {
       writeByte(Tag.SpecializedVariableGet + index);
@@ -1402,9 +1407,7 @@
 
   @override
   void visitVariableSet(VariableSet node) {
-    _variableIndexer ??= new VariableIndexer();
-    int index = _variableIndexer[node.variable];
-    assert(index != null, "No index found for ${node.variable}");
+    int index = _getVariableIndex(node.variable);
     if (index & Tag.SpecializedPayloadMask == index) {
       writeByte(Tag.SpecializedVariableSet + index);
       writeOffset(node.fileOffset);
@@ -1420,6 +1423,37 @@
   }
 
   @override
+  void visitDynamicGet(DynamicGet node) {
+    writeByte(Tag.DynamicGet);
+    writeByte(node.kind.index);
+    writeOffset(node.fileOffset);
+    writeNode(node.receiver);
+    writeName(node.name);
+  }
+
+  @override
+  void visitInstanceGet(InstanceGet node) {
+    writeByte(Tag.InstanceGet);
+    writeByte(node.kind.index);
+    writeOffset(node.fileOffset);
+    writeNode(node.receiver);
+    writeName(node.name);
+    writeDartType(node.resultType);
+    writeNonNullInstanceMemberReference(node.interfaceTargetReference);
+  }
+
+  @override
+  void visitInstanceTearOff(InstanceTearOff node) {
+    writeByte(Tag.InstanceTearOff);
+    writeByte(node.kind.index);
+    writeOffset(node.fileOffset);
+    writeNode(node.receiver);
+    writeName(node.name);
+    writeDartType(node.resultType);
+    writeNonNullInstanceMemberReference(node.interfaceTargetReference);
+  }
+
+  @override
   void visitPropertyGet(PropertyGet node) {
     writeByte(Tag.PropertyGet);
     writeOffset(node.fileOffset);
@@ -1429,6 +1463,27 @@
   }
 
   @override
+  void visitDynamicSet(DynamicSet node) {
+    writeByte(Tag.DynamicSet);
+    writeByte(node.kind.index);
+    writeOffset(node.fileOffset);
+    writeNode(node.receiver);
+    writeName(node.name);
+    writeNode(node.value);
+  }
+
+  @override
+  void visitInstanceSet(InstanceSet node) {
+    writeByte(Tag.InstanceSet);
+    writeByte(node.kind.index);
+    writeOffset(node.fileOffset);
+    writeNode(node.receiver);
+    writeName(node.name);
+    writeNode(node.value);
+    writeNonNullInstanceMemberReference(node.interfaceTargetReference);
+  }
+
+  @override
   void visitPropertySet(PropertySet node) {
     writeByte(Tag.PropertySet);
     writeOffset(node.fileOffset);
@@ -1463,6 +1518,13 @@
   }
 
   @override
+  void visitStaticTearOff(StaticTearOff node) {
+    writeByte(Tag.StaticTearOff);
+    writeOffset(node.fileOffset);
+    writeNonNullReference(node.targetReference);
+  }
+
+  @override
   void visitStaticSet(StaticSet node) {
     writeByte(Tag.StaticSet);
     writeOffset(node.fileOffset);
@@ -1471,6 +1533,70 @@
   }
 
   @override
+  void visitDynamicInvocation(DynamicInvocation node) {
+    writeByte(Tag.DynamicInvocation);
+    writeByte(node.kind.index);
+    writeOffset(node.fileOffset);
+    writeNode(node.receiver);
+    writeName(node.name);
+    writeArgumentsNode(node.arguments);
+  }
+
+  @override
+  void visitEqualsCall(EqualsCall node) {
+    writeByte(Tag.EqualsCall);
+    writeOffset(node.fileOffset);
+    writeNode(node.left);
+    writeNode(node.right);
+    writeByte(node.isNot ? 1 : 0);
+    writeDartType(node.functionType);
+    writeNonNullInstanceMemberReference(node.interfaceTargetReference);
+  }
+
+  @override
+  void visitEqualsNull(EqualsNull node) {
+    writeByte(Tag.EqualsNull);
+    writeOffset(node.fileOffset);
+    writeNode(node.expression);
+    writeByte(node.isNot ? 1 : 0);
+  }
+
+  @override
+  void visitFunctionInvocation(FunctionInvocation node) {
+    writeByte(Tag.FunctionInvocation);
+    writeByte(node.kind.index);
+    writeOffset(node.fileOffset);
+    writeNode(node.receiver);
+    writeArgumentsNode(node.arguments);
+    // `const DynamicType()` is used to encode a missing function type.
+    writeDartType(node.functionType ?? const DynamicType());
+  }
+
+  @override
+  void visitInstanceInvocation(InstanceInvocation node) {
+    writeByte(Tag.InstanceInvocation);
+    writeByte(node.kind.index);
+    writeByte(node.flags);
+    writeOffset(node.fileOffset);
+    writeNode(node.receiver);
+    writeName(node.name);
+    writeArgumentsNode(node.arguments);
+    writeDartType(node.functionType);
+    writeNonNullInstanceMemberReference(node.interfaceTargetReference);
+  }
+
+  @override
+  void visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+    writeByte(Tag.LocalFunctionInvocation);
+    writeOffset(node.fileOffset);
+    int index = _getVariableIndex(node.variable);
+    writeUInt30(node.variable.binaryOffsetNoTag);
+    writeUInt30(index);
+    writeArgumentsNode(node.arguments);
+    writeDartType(node.functionType);
+  }
+
+  @override
   void visitMethodInvocation(MethodInvocation node) {
     writeByte(Tag.MethodInvocation);
     writeByte(node.flags);
@@ -2238,6 +2364,13 @@
     }
   }
 
+  @override
+  void visitFunctionTearOff(FunctionTearOff node) {
+    writeByte(Tag.FunctionTearOff);
+    writeOffset(node.fileOffset);
+    writeNode(node.receiver);
+  }
+
   // ================================================================
   // These are nodes that are never serialized directly.  Reaching one
   // during serialization is an error.
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index 5fa202a..6c9b2c1 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -29,6 +29,9 @@
   // Expressions
   static const int CheckLibraryIsLoaded = 13;
   static const int LoadLibrary = 14;
+  static const int EqualsNull = 15;
+  static const int EqualsCall = 16;
+  static const int StaticTearOff = 17;
   static const int ConstStaticInvocation = 18;
   static const int InvalidExpression = 19;
   static const int VariableGet = 20;
@@ -45,14 +48,9 @@
   static const int ConstructorInvocation = 31;
   static const int ConstConstructorInvocation = 32;
   static const int Not = 33;
-  static const int NullCheck = 117;
   static const int LogicalExpression = 34;
   static const int ConditionalExpression = 35;
   static const int StringConcatenation = 36;
-  static const int ListConcatenation = 111;
-  static const int SetConcatenation = 112;
-  static const int MapConcatenation = 113;
-  static const int InstanceCreation = 114;
   static const int IsExpression = 37;
   static const int AsExpression = 38;
   static const int StringLiteral = 39;
@@ -77,10 +75,28 @@
   static const int BigIntLiteral = 57;
   static const int ConstListLiteral = 58;
   static const int ConstMapLiteral = 59;
+
   static const int SetLiteral = 109;
   static const int ConstSetLiteral = 110;
+  static const int ListConcatenation = 111;
+  static const int SetConcatenation = 112;
+  static const int MapConcatenation = 113;
+  static const int InstanceCreation = 114;
   static const int FileUriExpression = 116;
 
+  /// 115 is occupied by [Extension].
+  static const int NullCheck = 117;
+  static const int InstanceGet = 118;
+  static const int InstanceSet = 119;
+  static const int InstanceInvocation = 120;
+  static const int InstanceTearOff = 121;
+  static const int DynamicGet = 122;
+  static const int DynamicSet = 123;
+  static const int DynamicInvocation = 124;
+  static const int FunctionInvocation = 125;
+  static const int FunctionTearOff = 126;
+  static const int LocalFunctionInvocation = 127;
+
   // Statements
   static const int ExpressionStatement = 61;
   static const int Block = 62;
@@ -130,6 +146,16 @@
   /// 115 is occupied by [Extension].
   /// 116 is occupied by [FileUriExpression] (expression).
   /// 117 is occupied by [NullCheck] (expression).
+  /// 118 is occupied by [InstanceGet] (expression).
+  /// 119 is occupied by [InstanceSet] (expression).
+  /// 120 is occupied by [InstanceInvocation] (expression).
+  /// 121 is occupied by [InstanceTearOff] (expression).
+  /// 122 is occupied by [DynamicGet] (expression).
+  /// 123 is occupied by [DynamicSet] (expression).
+  /// 124 is occupied by [DynamicInvocation] (expression).
+  /// 125 is occupied by [FunctionInvocation] (expression).
+  /// 126 is occupied by [FunctionTearOff] (expression).
+  /// 127 is occupied by [LocalFunctionInvocation] (expression).
 
   static const int SpecializedTagHighBit = 0x80; // 10000000
   static const int SpecializedTagMask = 0xF8; // 11111000
@@ -146,7 +172,7 @@
   /// Internal version of kernel binary format.
   /// Bump it when making incompatible changes in kernel binaries.
   /// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
-  static const int BinaryFormatVersion = 52;
+  static const int BinaryFormatVersion = 53;
 }
 
 abstract class ConstantTag {
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index 3371d54..e5fc340 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -615,6 +615,91 @@
   visitTypedef(Typedef node) {
     return defaultTreeNode(node);
   }
+
+  @override
+  TreeNode visitDynamicGet(DynamicGet node) {
+    return new DynamicGet(node.kind, clone(node.receiver), node.name);
+  }
+
+  @override
+  TreeNode visitDynamicInvocation(DynamicInvocation node) {
+    return new DynamicInvocation(
+        node.kind, clone(node.receiver), node.name, clone(node.arguments));
+  }
+
+  @override
+  TreeNode visitDynamicSet(DynamicSet node) {
+    return new DynamicSet(
+        node.kind, clone(node.receiver), node.name, clone(node.value));
+  }
+
+  @override
+  TreeNode visitEqualsCall(EqualsCall node) {
+    return new EqualsCall.byReference(clone(node.left), clone(node.right),
+        isNot: node.isNot,
+        functionType: visitOptionalType(node.functionType),
+        interfaceTargetReference: node.interfaceTargetReference);
+  }
+
+  @override
+  TreeNode visitEqualsNull(EqualsNull node) {
+    return new EqualsNull(clone(node.expression), isNot: node.isNot);
+  }
+
+  @override
+  TreeNode visitFunctionInvocation(FunctionInvocation node) {
+    return new FunctionInvocation(
+        node.kind, clone(node.receiver), clone(node.arguments),
+        functionType: visitOptionalType(node.functionType));
+  }
+
+  @override
+  TreeNode visitInstanceGet(InstanceGet node) {
+    return new InstanceGet.byReference(
+        node.kind, clone(node.receiver), node.name,
+        resultType: visitOptionalType(node.resultType),
+        interfaceTargetReference: node.interfaceTargetReference);
+  }
+
+  @override
+  TreeNode visitInstanceInvocation(InstanceInvocation node) {
+    return new InstanceInvocation.byReference(
+        node.kind, clone(node.receiver), node.name, clone(node.arguments),
+        functionType: visitOptionalType(node.functionType),
+        interfaceTargetReference: node.interfaceTargetReference);
+  }
+
+  @override
+  TreeNode visitInstanceSet(InstanceSet node) {
+    return new InstanceSet.byReference(
+        node.kind, clone(node.receiver), node.name, clone(node.value),
+        interfaceTargetReference: node.interfaceTargetReference);
+  }
+
+  @override
+  TreeNode visitInstanceTearOff(InstanceTearOff node) {
+    return new InstanceTearOff.byReference(
+        node.kind, clone(node.receiver), node.name,
+        resultType: visitOptionalType(node.resultType),
+        interfaceTargetReference: node.interfaceTargetReference);
+  }
+
+  @override
+  TreeNode visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+    return new LocalFunctionInvocation(
+        variables[node.variable], clone(node.arguments),
+        functionType: visitOptionalType(node.functionType));
+  }
+
+  @override
+  TreeNode visitStaticTearOff(StaticTearOff node) {
+    return new StaticTearOff.byReference(node.targetReference);
+  }
+
+  @override
+  TreeNode visitFunctionTearOff(FunctionTearOff node) {
+    return new FunctionTearOff(clone(node.receiver));
+  }
 }
 
 /// Visitor that return a clone of a tree, maintaining references to cloned
diff --git a/pkg/kernel/lib/naive_type_checker.dart b/pkg/kernel/lib/naive_type_checker.dart
index 6f8d66d..76479c2 100644
--- a/pkg/kernel/lib/naive_type_checker.dart
+++ b/pkg/kernel/lib/naive_type_checker.dart
@@ -281,12 +281,18 @@
 
     // Permit any invocation on Function type.
     if (receiver == environment.coreTypes.functionLegacyRawType &&
-        where is MethodInvocation &&
+        where is InvocationExpression &&
         where.name.text == 'call') {
       return;
     }
 
-    fail(where, 'Unresolved method invocation');
+    if (receiver is FunctionType &&
+        where is InvocationExpression &&
+        where.name.text == 'call') {
+      return;
+    }
+
+    fail(where, 'Unresolved method invocation on ${receiver}');
   }
 
   @override
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index be01ba0..8018658 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -367,6 +367,8 @@
   /// with the accessed getter or field as the interface target.
   bool get supportsExplicitGetterCalls;
 
+  bool get supportsNewMethodInvocationEncoding;
+
   /// Builds an expression that instantiates an [Invocation] that can be passed
   /// to [noSuchMethod].
   Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver,
@@ -434,6 +436,9 @@
       !flags.forceNoExplicitGetterCallsForTesting;
 
   @override
+  bool get supportsNewMethodInvocationEncoding => true;
+
+  @override
   String get name => 'none';
 
   @override
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index b9d95ab..fe7b594 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -1350,6 +1350,120 @@
     }
   }
 
+  void _writeDynamicAccessKind(DynamicAccessKind kind) {
+    switch (kind) {
+      case DynamicAccessKind.Dynamic:
+        writeSymbol('{dynamic}.');
+        break;
+      case DynamicAccessKind.Never:
+        writeSymbol('{Never}.');
+        break;
+      case DynamicAccessKind.Invalid:
+        writeSymbol('{<invalid>}.');
+        break;
+      case DynamicAccessKind.Unresolved:
+        writeSymbol('{<unresolved>}.');
+        break;
+    }
+  }
+
+  visitDynamicInvocation(DynamicInvocation node) {
+    writeExpression(node.receiver, Precedence.PRIMARY);
+    _writeDynamicAccessKind(node.kind);
+    writeName(
+      node.name,
+    );
+    writeNode(node.arguments);
+  }
+
+  void _writeFunctionAccessKind(FunctionAccessKind kind) {
+    switch (kind) {
+      case FunctionAccessKind.Function:
+      case FunctionAccessKind.FunctionType:
+        break;
+      case FunctionAccessKind.Inapplicable:
+        writeSymbol('{<inapplicable>}.');
+        break;
+      case FunctionAccessKind.Nullable:
+        writeSymbol('{<nullable>}.');
+        break;
+    }
+  }
+
+  visitFunctionInvocation(FunctionInvocation node) {
+    writeExpression(node.receiver, Precedence.PRIMARY);
+    _writeFunctionAccessKind(node.kind);
+    writeNode(node.arguments);
+    if (node.functionType != null) {
+      writeSymbol('{');
+      writeType(node.functionType);
+      writeSymbol('}');
+    }
+  }
+
+  @override
+  visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+    writeVariableReference(node.variable);
+    writeNode(node.arguments);
+    writeSymbol('{');
+    writeType(node.functionType);
+    writeSymbol('}');
+  }
+
+  void _writeInstanceAccessKind(InstanceAccessKind kind) {
+    switch (kind) {
+      case InstanceAccessKind.Instance:
+      case InstanceAccessKind.Object:
+        break;
+      case InstanceAccessKind.Inapplicable:
+        writeSymbol('{<inapplicable>}.');
+        break;
+      case InstanceAccessKind.Nullable:
+        writeSymbol('{<nullable>}.');
+        break;
+    }
+  }
+
+  visitInstanceInvocation(InstanceInvocation node) {
+    writeExpression(node.receiver, Precedence.PRIMARY);
+    writeSymbol('.');
+    writeInterfaceTarget(node.name, node.interfaceTargetReference);
+    _writeInstanceAccessKind(node.kind);
+    writeNode(node.arguments);
+    writeSymbol('{');
+    writeType(node.functionType);
+    writeSymbol('}');
+  }
+
+  visitEqualsCall(EqualsCall node) {
+    int precedence = Precedence.EQUALITY;
+    writeExpression(node.left, precedence);
+    writeSpace();
+    if (node.isNot) {
+      writeSymbol('!=');
+    } else {
+      writeSymbol('==');
+    }
+    writeInterfaceTarget(Name.equalsName, node.interfaceTargetReference);
+    writeSymbol('{');
+    writeType(node.functionType);
+    writeSymbol('}');
+    writeSpace();
+    writeExpression(node.right, precedence + 1);
+  }
+
+  visitEqualsNull(EqualsNull node) {
+    writeExpression(node.expression, Precedence.EQUALITY);
+    writeSpace();
+    if (node.isNot) {
+      writeSymbol('!=');
+    } else {
+      writeSymbol('==');
+    }
+    writeSpace();
+    writeSymbol('null');
+  }
+
   visitMethodInvocation(MethodInvocation node) {
     writeExpression(node.receiver, Precedence.PRIMARY);
     writeSymbol('.');
@@ -1758,12 +1872,61 @@
     }
   }
 
+  visitDynamicGet(DynamicGet node) {
+    writeExpression(node.receiver, Precedence.PRIMARY);
+    _writeDynamicAccessKind(node.kind);
+    writeName(node.name);
+  }
+
+  visitFunctionTearOff(FunctionTearOff node) {
+    writeExpression(node.receiver, Precedence.PRIMARY);
+    writeSymbol('.');
+    writeSymbol('call');
+  }
+
+  visitInstanceGet(InstanceGet node) {
+    writeExpression(node.receiver, Precedence.PRIMARY);
+    writeSymbol('.');
+    writeInterfaceTarget(node.name, node.interfaceTargetReference);
+    _writeInstanceAccessKind(node.kind);
+    writeSymbol('{');
+    writeType(node.resultType);
+    writeSymbol('}');
+  }
+
+  visitInstanceTearOff(InstanceTearOff node) {
+    writeExpression(node.receiver, Precedence.PRIMARY);
+    writeSymbol('.');
+    writeInterfaceTarget(node.name, node.interfaceTargetReference);
+    _writeInstanceAccessKind(node.kind);
+    writeSymbol('{');
+    writeType(node.resultType);
+    writeSymbol('}');
+  }
+
   visitPropertyGet(PropertyGet node) {
     writeExpression(node.receiver, Precedence.PRIMARY);
     writeSymbol('.');
     writeInterfaceTarget(node.name, node.interfaceTargetReference);
   }
 
+  visitDynamicSet(DynamicSet node) {
+    writeExpression(node.receiver, Precedence.PRIMARY);
+    _writeDynamicAccessKind(node.kind);
+    writeName(node.name);
+    writeSpaced('=');
+    writeExpression(node.value);
+  }
+
+  visitInstanceSet(InstanceSet node) {
+    writeExpression(node.receiver, Precedence.PRIMARY);
+    writeSymbol('.');
+    writeInterfaceTarget(node.name, node.interfaceTargetReference);
+    _writeInstanceAccessKind(node.kind);
+    writeSpaced('=');
+    writeExpression(node.value);
+  }
+
   visitPropertySet(PropertySet node) {
     writeExpression(node.receiver, Precedence.PRIMARY);
     writeSymbol('.');
@@ -1786,6 +1949,10 @@
     writeExpression(node.value);
   }
 
+  visitStaticTearOff(StaticTearOff node) {
+    writeMemberReferenceFromReference(node.targetReference);
+  }
+
   visitStaticGet(StaticGet node) {
     writeMemberReferenceFromReference(node.targetReference);
   }
@@ -2426,7 +2593,7 @@
   }
 }
 
-class Precedence extends ExpressionVisitor<int> {
+class Precedence implements ExpressionVisitor<int> {
   static final Precedence instance = new Precedence();
 
   static int of(Expression node) => node.accept(instance);
@@ -2478,44 +2645,189 @@
     return precedence != EQUALITY && precedence != RELATIONAL;
   }
 
+  @override
   int defaultExpression(Expression node) => EXPRESSION;
+
+  @override
   int visitInvalidExpression(InvalidExpression node) => CALLEE;
+
+  @override
   int visitMethodInvocation(MethodInvocation node) => CALLEE;
+
+  @override
+  int visitInstanceInvocation(InstanceInvocation node) => CALLEE;
+
+  @override
+  int visitDynamicInvocation(DynamicInvocation node) => CALLEE;
+
+  @override
+  int visitFunctionInvocation(FunctionInvocation node) => CALLEE;
+
+  @override
+  int visitLocalFunctionInvocation(LocalFunctionInvocation node) => CALLEE;
+
+  @override
+  int visitEqualsCall(EqualsCall node) => EQUALITY;
+
+  @override
+  int visitEqualsNull(EqualsNull node) => EQUALITY;
+
+  @override
   int visitSuperMethodInvocation(SuperMethodInvocation node) => CALLEE;
+
+  @override
   int visitStaticInvocation(StaticInvocation node) => CALLEE;
+
+  @override
   int visitConstructorInvocation(ConstructorInvocation node) => CALLEE;
+
+  @override
   int visitNot(Not node) => PREFIX;
+
+  @override
   int visitNullCheck(NullCheck node) => PRIMARY;
+
+  @override
   int visitLogicalExpression(LogicalExpression node) =>
       binaryPrecedence[logicalExpressionOperatorToString(node.operatorEnum)];
+
+  @override
   int visitConditionalExpression(ConditionalExpression node) => CONDITIONAL;
+
+  @override
   int visitStringConcatenation(StringConcatenation node) => PRIMARY;
+
+  @override
   int visitIsExpression(IsExpression node) => RELATIONAL;
+
+  @override
   int visitAsExpression(AsExpression node) => RELATIONAL;
+
+  @override
   int visitSymbolLiteral(SymbolLiteral node) => PRIMARY;
+
+  @override
   int visitTypeLiteral(TypeLiteral node) => PRIMARY;
+
+  @override
   int visitThisExpression(ThisExpression node) => CALLEE;
+
+  @override
   int visitRethrow(Rethrow node) => PRIMARY;
+
+  @override
   int visitThrow(Throw node) => EXPRESSION;
+
+  @override
   int visitListLiteral(ListLiteral node) => PRIMARY;
+
+  @override
   int visitSetLiteral(SetLiteral node) => PRIMARY;
+
+  @override
   int visitMapLiteral(MapLiteral node) => PRIMARY;
+
+  @override
   int visitAwaitExpression(AwaitExpression node) => PREFIX;
+
+  @override
   int visitFunctionExpression(FunctionExpression node) => EXPRESSION;
+
+  @override
   int visitStringLiteral(StringLiteral node) => CALLEE;
+
+  @override
   int visitIntLiteral(IntLiteral node) => CALLEE;
+
+  @override
   int visitDoubleLiteral(DoubleLiteral node) => CALLEE;
+
+  @override
   int visitBoolLiteral(BoolLiteral node) => CALLEE;
+
+  @override
   int visitNullLiteral(NullLiteral node) => CALLEE;
+
+  @override
   int visitVariableGet(VariableGet node) => PRIMARY;
+
+  @override
   int visitVariableSet(VariableSet node) => EXPRESSION;
+
+  @override
   int visitPropertyGet(PropertyGet node) => PRIMARY;
+
+  @override
+  int visitInstanceGet(InstanceGet node) => PRIMARY;
+
+  @override
+  int visitDynamicGet(DynamicGet node) => PRIMARY;
+
+  @override
+  int visitInstanceTearOff(InstanceTearOff node) => PRIMARY;
+
+  @override
+  int visitFunctionTearOff(FunctionTearOff node) => PRIMARY;
+
+  @override
   int visitPropertySet(PropertySet node) => EXPRESSION;
+
+  @override
   int visitSuperPropertyGet(SuperPropertyGet node) => PRIMARY;
+
+  @override
   int visitSuperPropertySet(SuperPropertySet node) => EXPRESSION;
+
+  @override
   int visitStaticGet(StaticGet node) => PRIMARY;
+
+  @override
+  int visitStaticTearOff(StaticTearOff node) => PRIMARY;
+
+  @override
   int visitStaticSet(StaticSet node) => EXPRESSION;
+
+  @override
   int visitLet(Let node) => EXPRESSION;
+
+  @override
+  int defaultBasicLiteral(BasicLiteral node) => CALLEE;
+
+  @override
+  int visitBlockExpression(BlockExpression node) => EXPRESSION;
+
+  @override
+  int visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) => EXPRESSION;
+
+  @override
+  int visitConstantExpression(ConstantExpression node) => EXPRESSION;
+
+  @override
+  int visitDynamicSet(DynamicSet node) => EXPRESSION;
+
+  @override
+  int visitFileUriExpression(FileUriExpression node) => EXPRESSION;
+
+  @override
+  int visitInstanceCreation(InstanceCreation node) => EXPRESSION;
+
+  @override
+  int visitInstanceSet(InstanceSet node) => EXPRESSION;
+
+  @override
+  int visitInstantiation(Instantiation node) => EXPRESSION;
+
+  @override
+  int visitListConcatenation(ListConcatenation node) => EXPRESSION;
+
+  @override
+  int visitLoadLibrary(LoadLibrary node) => EXPRESSION;
+
+  @override
+  int visitMapConcatenation(MapConcatenation node) => EXPRESSION;
+
+  @override
+  int visitSetConcatenation(SetConcatenation node) => EXPRESSION;
 }
 
 String procedureKindToString(ProcedureKind kind) {
diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
index 0e24e6f..e68e340 100644
--- a/pkg/kernel/lib/type_checker.dart
+++ b/pkg/kernel/lib/type_checker.dart
@@ -1076,4 +1076,122 @@
 
   @override
   visitInvalidInitializer(InvalidInitializer node) {}
+
+  @override
+  DartType visitDynamicGet(DynamicGet node) {
+    DartType receiverType = visitExpression(node.receiver);
+    checkUnresolvedInvocation(receiverType, node);
+    return const DynamicType();
+  }
+
+  @override
+  DartType visitDynamicInvocation(DynamicInvocation node) {
+    DartType receiverType = visitExpression(node.receiver);
+    checkUnresolvedInvocation(receiverType, node);
+    node.arguments.positional.forEach(visitExpression);
+    node.arguments.named
+        .forEach((NamedExpression n) => visitExpression(n.value));
+    return const DynamicType();
+  }
+
+  @override
+  DartType visitDynamicSet(DynamicSet node) {
+    DartType value = visitExpression(node.value);
+    final DartType receiver = visitExpression(node.receiver);
+    checkUnresolvedInvocation(receiver, node);
+    return value;
+  }
+
+  @override
+  DartType visitEqualsCall(EqualsCall node) {
+    visitExpression(node.left);
+    visitExpression(node.right);
+    // TODO(johnniwinther): Return Never as type for equals call on Never.
+    return environment.coreTypes.boolLegacyRawType;
+  }
+
+  @override
+  DartType visitEqualsNull(EqualsNull node) {
+    visitExpression(node.expression);
+    return environment.coreTypes.boolLegacyRawType;
+  }
+
+  @override
+  DartType visitFunctionInvocation(FunctionInvocation node) {
+    DartType receiverType = visitExpression(node.receiver);
+    checkUnresolvedInvocation(receiverType, node);
+    node.arguments.positional.forEach(visitExpression);
+    node.arguments.named
+        .forEach((NamedExpression n) => visitExpression(n.value));
+    // TODO(johnniwinther): Return the correct result type.
+    return const DynamicType();
+  }
+
+  @override
+  DartType visitInstanceGet(InstanceGet node) {
+    Substitution receiver =
+        getReceiverType(node, node.receiver, node.interfaceTarget);
+    return receiver.substituteType(node.interfaceTarget.getterType);
+  }
+
+  @override
+  DartType visitInstanceInvocation(InstanceInvocation node) {
+    // TODO(johnniwinther): Use embedded static type.
+    Member target = node.interfaceTarget;
+    if (target is Procedure &&
+        environment.isSpecialCasedBinaryOperator(target)) {
+      assert(node.arguments.positional.length == 1);
+      DartType receiver = visitExpression(node.receiver);
+      DartType argument = visitExpression(node.arguments.positional[0]);
+      return environment.getTypeOfSpecialCasedBinaryOperator(
+          receiver, argument);
+    } else {
+      visitExpression(node.receiver);
+      return handleCall(node.arguments, target.getterType,
+          receiver: getReceiverType(node, node.receiver, node.interfaceTarget));
+    }
+  }
+
+  @override
+  DartType visitInstanceSet(InstanceSet node) {
+    DartType value = visitExpression(node.value);
+    Substitution receiver =
+        getReceiverType(node, node.receiver, node.interfaceTarget);
+    checkAssignable(
+        node.value,
+        value,
+        receiver.substituteType(node.interfaceTarget.setterType,
+            contravariant: true));
+    return value;
+  }
+
+  @override
+  DartType visitInstanceTearOff(InstanceTearOff node) {
+    Substitution receiver =
+        getReceiverType(node, node.receiver, node.interfaceTarget);
+    return receiver.substituteType(node.interfaceTarget.getterType);
+  }
+
+  @override
+  DartType visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+    checkUnresolvedInvocation(node.functionType, node);
+    node.arguments.positional.forEach(visitExpression);
+    node.arguments.named
+        .forEach((NamedExpression n) => visitExpression(n.value));
+    // TODO(johnniwinther): Return the correct result type.
+    return const DynamicType();
+  }
+
+  @override
+  DartType visitStaticTearOff(StaticTearOff node) {
+    return node.target.getterType;
+  }
+
+  @override
+  DartType visitFunctionTearOff(FunctionTearOff node) {
+    DartType receiverType = visitExpression(node.receiver);
+    checkUnresolvedInvocation(receiverType, node);
+    // TODO(johnniwinther): Return the correct result type.
+    return const DynamicType();
+  }
 }
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index fdabdc6..a8e984a 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -17,12 +17,26 @@
   R visitInvalidExpression(InvalidExpression node) => defaultExpression(node);
   R visitVariableGet(VariableGet node) => defaultExpression(node);
   R visitVariableSet(VariableSet node) => defaultExpression(node);
+  R visitDynamicGet(DynamicGet node) => defaultExpression(node);
+  R visitDynamicSet(DynamicSet node) => defaultExpression(node);
+  R visitFunctionTearOff(FunctionTearOff node) => defaultExpression(node);
+  R visitInstanceGet(InstanceGet node) => defaultExpression(node);
+  R visitInstanceSet(InstanceSet node) => defaultExpression(node);
+  R visitInstanceTearOff(InstanceTearOff node) => defaultExpression(node);
   R visitPropertyGet(PropertyGet node) => defaultExpression(node);
   R visitPropertySet(PropertySet node) => defaultExpression(node);
   R visitSuperPropertyGet(SuperPropertyGet node) => defaultExpression(node);
   R visitSuperPropertySet(SuperPropertySet node) => defaultExpression(node);
   R visitStaticGet(StaticGet node) => defaultExpression(node);
   R visitStaticSet(StaticSet node) => defaultExpression(node);
+  R visitStaticTearOff(StaticTearOff node) => defaultExpression(node);
+  R visitLocalFunctionInvocation(LocalFunctionInvocation node) =>
+      defaultExpression(node);
+  R visitDynamicInvocation(DynamicInvocation node) => defaultExpression(node);
+  R visitFunctionInvocation(FunctionInvocation node) => defaultExpression(node);
+  R visitInstanceInvocation(InstanceInvocation node) => defaultExpression(node);
+  R visitEqualsNull(EqualsNull node) => defaultExpression(node);
+  R visitEqualsCall(EqualsCall node) => defaultExpression(node);
   R visitMethodInvocation(MethodInvocation node) => defaultExpression(node);
   R visitSuperMethodInvocation(SuperMethodInvocation node) =>
       defaultExpression(node);
@@ -142,12 +156,26 @@
   R visitInvalidExpression(InvalidExpression node) => defaultExpression(node);
   R visitVariableGet(VariableGet node) => defaultExpression(node);
   R visitVariableSet(VariableSet node) => defaultExpression(node);
+  R visitDynamicGet(DynamicGet node) => defaultExpression(node);
+  R visitDynamicSet(DynamicSet node) => defaultExpression(node);
+  R visitFunctionTearOff(FunctionTearOff node) => defaultExpression(node);
+  R visitInstanceGet(InstanceGet node) => defaultExpression(node);
+  R visitInstanceSet(InstanceSet node) => defaultExpression(node);
+  R visitInstanceTearOff(InstanceTearOff node) => defaultExpression(node);
   R visitPropertyGet(PropertyGet node) => defaultExpression(node);
   R visitPropertySet(PropertySet node) => defaultExpression(node);
   R visitSuperPropertyGet(SuperPropertyGet node) => defaultExpression(node);
   R visitSuperPropertySet(SuperPropertySet node) => defaultExpression(node);
   R visitStaticGet(StaticGet node) => defaultExpression(node);
   R visitStaticSet(StaticSet node) => defaultExpression(node);
+  R visitStaticTearOff(StaticTearOff node) => defaultExpression(node);
+  R visitLocalFunctionInvocation(LocalFunctionInvocation node) =>
+      defaultExpression(node);
+  R visitDynamicInvocation(DynamicInvocation node) => defaultExpression(node);
+  R visitFunctionInvocation(FunctionInvocation node) => defaultExpression(node);
+  R visitInstanceInvocation(InstanceInvocation node) => defaultExpression(node);
+  R visitEqualsNull(EqualsNull node) => defaultExpression(node);
+  R visitEqualsCall(EqualsCall node) => defaultExpression(node);
   R visitMethodInvocation(MethodInvocation node) => defaultExpression(node);
   R visitSuperMethodInvocation(SuperMethodInvocation node) =>
       defaultExpression(node);
@@ -661,6 +689,14 @@
       defaultExpression(node, arg);
   R visitVariableGet(VariableGet node, T arg) => defaultExpression(node, arg);
   R visitVariableSet(VariableSet node, T arg) => defaultExpression(node, arg);
+  R visitDynamicGet(DynamicGet node, T arg) => defaultExpression(node, arg);
+  R visitDynamicSet(DynamicSet node, T arg) => defaultExpression(node, arg);
+  R visitFunctionTearOff(FunctionTearOff node, T arg) =>
+      defaultExpression(node, arg);
+  R visitInstanceGet(InstanceGet node, T arg) => defaultExpression(node, arg);
+  R visitInstanceSet(InstanceSet node, T arg) => defaultExpression(node, arg);
+  R visitInstanceTearOff(InstanceTearOff node, T arg) =>
+      defaultExpression(node, arg);
   R visitPropertyGet(PropertyGet node, T arg) => defaultExpression(node, arg);
   R visitPropertySet(PropertySet node, T arg) => defaultExpression(node, arg);
   R visitSuperPropertyGet(SuperPropertyGet node, T arg) =>
@@ -669,6 +705,18 @@
       defaultExpression(node, arg);
   R visitStaticGet(StaticGet node, T arg) => defaultExpression(node, arg);
   R visitStaticSet(StaticSet node, T arg) => defaultExpression(node, arg);
+  R visitStaticTearOff(StaticTearOff node, T arg) =>
+      defaultExpression(node, arg);
+  R visitLocalFunctionInvocation(LocalFunctionInvocation node, T arg) =>
+      defaultExpression(node, arg);
+  R visitDynamicInvocation(DynamicInvocation node, T arg) =>
+      defaultExpression(node, arg);
+  R visitFunctionInvocation(FunctionInvocation node, T arg) =>
+      defaultExpression(node, arg);
+  R visitInstanceInvocation(InstanceInvocation node, T arg) =>
+      defaultExpression(node, arg);
+  R visitEqualsNull(EqualsNull node, T arg) => defaultExpression(node, arg);
+  R visitEqualsCall(EqualsCall node, T arg) => defaultExpression(node, arg);
   R visitMethodInvocation(MethodInvocation node, T arg) =>
       defaultExpression(node, arg);
   R visitSuperMethodInvocation(SuperMethodInvocation node, T arg) =>
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index c117efa..d943670 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -22,7 +22,6 @@
 
 import '../transformations/call_site_annotator.dart' as callSiteAnnotator;
 import '../transformations/lowering.dart' as lowering show transformLibraries;
-import '../transformations/ffi.dart' as transformFfi show ReplacedMembers;
 import '../transformations/ffi_definitions.dart' as transformFfiDefinitions
     show transformLibraries;
 import '../transformations/ffi_use_sites.dart' as transformFfiUseSites
@@ -64,6 +63,9 @@
       !flags.forceNoExplicitGetterCallsForTesting;
 
   @override
+  bool get supportsNewMethodInvocationEncoding => false;
+
+  @override
   String get name => 'vm';
 
   // This is the order that bootstrap libraries are loaded according to
@@ -152,17 +154,16 @@
         this, coreTypes, hierarchy, libraries, referenceFromIndex);
     logger?.call("Transformed mixin applications");
 
-    transformFfi.ReplacedMembers replacedFields =
-        transformFfiDefinitions.transformLibraries(
-            component,
-            coreTypes,
-            hierarchy,
-            libraries,
-            diagnosticReporter,
-            referenceFromIndex,
-            changedStructureNotifier);
+    final ffiTransformerData = transformFfiDefinitions.transformLibraries(
+        component,
+        coreTypes,
+        hierarchy,
+        libraries,
+        diagnosticReporter,
+        referenceFromIndex,
+        changedStructureNotifier);
     transformFfiUseSites.transformLibraries(component, coreTypes, hierarchy,
-        libraries, diagnosticReporter, replacedFields, referenceFromIndex);
+        libraries, diagnosticReporter, ffiTransformerData, referenceFromIndex);
     logger?.call("Transformed ffi annotations");
 
     // TODO(kmillikin): Make this run on a per-method basis.
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index 2752c23..7bdd598 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -310,8 +310,8 @@
   /// [Handle]                             -> [Object]
   /// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
   ///    where DartRepresentationOf(Tn) -> Sn
-  DartType convertNativeTypeToDartType(
-      DartType nativeType, bool allowStructs, bool allowHandle) {
+  DartType convertNativeTypeToDartType(DartType nativeType,
+      {bool allowStructs = false, bool allowHandle = false}) {
     if (nativeType is! InterfaceType) {
       return null;
     }
@@ -352,13 +352,13 @@
       return null;
     }
     if (fun.typeParameters.length != 0) return null;
-    // TODO(36730): Structs cannot appear in native function signatures.
-    final DartType returnType = convertNativeTypeToDartType(
-        fun.returnType, /*allowStructs=*/ false, /*allowHandle=*/ true);
+
+    final DartType returnType = convertNativeTypeToDartType(fun.returnType,
+        allowStructs: allowStructs, allowHandle: true);
     if (returnType == null) return null;
     final List<DartType> argumentTypes = fun.positionalParameters
-        .map((t) => convertNativeTypeToDartType(
-            t, /*allowStructs=*/ false, /*allowHandle=*/ true))
+        .map((t) => convertNativeTypeToDartType(t,
+            allowStructs: allowStructs, allowHandle: true))
         .toList();
     if (argumentTypes.contains(null)) return null;
     return FunctionType(argumentTypes, returnType, Nullability.legacy);
@@ -373,12 +373,12 @@
   }
 }
 
-/// Contains replaced members, of which all the call sites need to be replaced.
-///
-/// [ReplacedMembers] is populated by _FfiDefinitionTransformer and consumed by
-/// _FfiUseSiteTransformer.
-class ReplacedMembers {
+/// Contains all information collected by _FfiDefinitionTransformer that is
+/// needed in _FfiUseSiteTransformer.
+class FfiTransformerData {
   final Map<Field, Procedure> replacedGetters;
   final Map<Field, Procedure> replacedSetters;
-  ReplacedMembers(this.replacedGetters, this.replacedSetters);
+  final Set<Class> emptyStructs;
+  FfiTransformerData(
+      this.replacedGetters, this.replacedSetters, this.emptyStructs);
 }
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index 4f96426..ec6849a 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -56,7 +56,7 @@
 ///
 ///   static final int #sizeOf = 24;
 /// }
-ReplacedMembers transformLibraries(
+FfiTransformerData transformLibraries(
     Component component,
     CoreTypes coreTypes,
     ClassHierarchy hierarchy,
@@ -70,17 +70,17 @@
     // TODO: This check doesn't make sense: "dart:ffi" is always loaded/created
     // for the VM target.
     // If dart:ffi is not loaded, do not do the transformation.
-    return ReplacedMembers({}, {});
+    return FfiTransformerData({}, {}, {});
   }
   if (index.tryGetClass('dart:ffi', 'NativeFunction') == null) {
     // If dart:ffi is not loaded (for real): do not do the transformation.
-    return ReplacedMembers({}, {});
+    return FfiTransformerData({}, {}, {});
   }
   final transformer = new _FfiDefinitionTransformer(index, coreTypes, hierarchy,
       diagnosticReporter, referenceFromIndex, changedStructureNotifier);
   libraries.forEach(transformer.visitLibrary);
-  return ReplacedMembers(
-      transformer.replacedGetters, transformer.replacedSetters);
+  return FfiTransformerData(transformer.replacedGetters,
+      transformer.replacedSetters, transformer.emptyStructs);
 }
 
 /// Checks and elaborates the dart:ffi structs and fields.
@@ -89,6 +89,7 @@
 
   Map<Field, Procedure> replacedGetters = {};
   Map<Field, Procedure> replacedSetters = {};
+  Set<Class> emptyStructs = {};
 
   ChangedStructureNotifier changedStructureNotifier;
 
@@ -231,7 +232,9 @@
             Nullability.legacy);
         // TODO(dartbug.com/37271): Support structs inside structs.
         final DartType shouldBeDartType = convertNativeTypeToDartType(
-            nativeType, /*allowStructs=*/ false, /*allowHandle=*/ false);
+            nativeType,
+            allowStructs: false,
+            allowHandle: false);
         if (shouldBeDartType == null ||
             !env.isSubtypeOf(type, shouldBeDartType,
                 SubtypeCheckMode.ignoringNullabilities)) {
@@ -338,6 +341,9 @@
     }
 
     _annoteStructWithFields(node, classes);
+    if (classes.isEmpty) {
+      emptyStructs.add(node);
+    }
 
     final sizeAndOffsets = <Abi, SizeAndOffsets>{};
     for (final Abi abi in Abi.values) {
@@ -565,6 +571,9 @@
     return offset;
   }
 
+  // Keep consistent with runtime/vm/compiler/ffi/native_type.cc
+  // NativeCompoundType::FromNativeTypes.
+  //
   // TODO(37271): Support nested structs.
   SizeAndOffsets _calculateSizeAndOffsets(List<NativeType> types, Abi abi) {
     int offset = 0;
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 16e31c7..f4a9c05 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -9,6 +9,7 @@
         messageFfiExceptionalReturnNull,
         messageFfiExpectedConstant,
         templateFfiDartTypeMismatch,
+        templateFfiEmptyStruct,
         templateFfiExpectedExceptionalReturn,
         templateFfiExpectedNoExceptionalReturn,
         templateFfiExtendsOrImplementsSealedClass,
@@ -25,7 +26,7 @@
 import 'package:kernel/type_environment.dart';
 
 import 'ffi.dart'
-    show ReplacedMembers, NativeType, FfiTransformer, optimizedTypes;
+    show FfiTransformerData, NativeType, FfiTransformer, optimizedTypes;
 
 /// Checks and replaces calls to dart:ffi struct fields and methods.
 void transformLibraries(
@@ -34,7 +35,7 @@
     ClassHierarchy hierarchy,
     List<Library> libraries,
     DiagnosticReporter diagnosticReporter,
-    ReplacedMembers replacedFields,
+    FfiTransformerData ffiTransformerData,
     ReferenceFromIndex referenceFromIndex) {
   final index = new LibraryIndex(component, ["dart:ffi"]);
   if (!index.containsLibrary("dart:ffi")) {
@@ -53,8 +54,9 @@
       hierarchy,
       diagnosticReporter,
       referenceFromIndex,
-      replacedFields.replacedGetters,
-      replacedFields.replacedSetters);
+      ffiTransformerData.replacedGetters,
+      ffiTransformerData.replacedSetters,
+      ffiTransformerData.emptyStructs);
   libraries.forEach(transformer.visitLibrary);
 }
 
@@ -62,6 +64,7 @@
 class _FfiUseSiteTransformer extends FfiTransformer {
   final Map<Field, Procedure> replacedGetters;
   final Map<Field, Procedure> replacedSetters;
+  final Set<Class> emptyStructs;
   StaticTypeContext _staticTypeContext;
 
   Library currentLibrary;
@@ -79,7 +82,8 @@
       DiagnosticReporter diagnosticReporter,
       ReferenceFromIndex referenceFromIndex,
       this.replacedGetters,
-      this.replacedSetters)
+      this.replacedSetters,
+      this.emptyStructs)
       : super(index, coreTypes, hierarchy, diagnosticReporter,
             referenceFromIndex) {}
 
@@ -171,18 +175,18 @@
             nativeFunctionClass, Nullability.legacy, [node.arguments.types[0]]);
         final DartType dartType = node.arguments.types[1];
 
-        _ensureNativeTypeValid(nativeType, node, allowStructs: false);
-        _ensureNativeTypeToDartType(nativeType, dartType, node,
-            allowStructs: false);
+        _ensureNativeTypeValid(nativeType, node);
+        _ensureNativeTypeToDartType(nativeType, dartType, node);
+        _ensureNoEmptyStructs(dartType, node);
         return _replaceLookupFunction(node);
       } else if (target == asFunctionMethod) {
         final DartType dartType = node.arguments.types[1];
         final DartType nativeType = InterfaceType(
             nativeFunctionClass, Nullability.legacy, [node.arguments.types[0]]);
 
-        _ensureNativeTypeValid(nativeType, node, allowStructs: false);
-        _ensureNativeTypeToDartType(nativeType, dartType, node,
-            allowStructs: false);
+        _ensureNativeTypeValid(nativeType, node);
+        _ensureNativeTypeToDartType(nativeType, dartType, node);
+        _ensureNoEmptyStructs(dartType, node);
 
         final DartType nativeSignature =
             (nativeType as InterfaceType).typeArguments[0];
@@ -199,9 +203,9 @@
 
         _ensureIsStaticFunction(func);
 
-        _ensureNativeTypeValid(nativeType, node, allowStructs: false);
-        _ensureNativeTypeToDartType(nativeType, dartType, node,
-            allowStructs: false);
+        _ensureNativeTypeValid(nativeType, node);
+        _ensureNativeTypeToDartType(nativeType, dartType, node);
+        _ensureNoEmptyStructs(dartType, node);
 
         // Check `exceptionalReturn`'s type.
         final FunctionType funcType = dartType;
@@ -394,9 +398,11 @@
 
   void _ensureNativeTypeToDartType(
       DartType nativeType, DartType dartType, Expression node,
-      {bool allowStructs: false, bool allowHandle: false}) {
-    final DartType correspondingDartType =
-        convertNativeTypeToDartType(nativeType, allowStructs, allowHandle);
+      {bool allowHandle: false}) {
+    final DartType correspondingDartType = convertNativeTypeToDartType(
+        nativeType,
+        allowStructs: true,
+        allowHandle: allowHandle);
     if (dartType == correspondingDartType) return;
     if (env.isSubtypeOf(correspondingDartType, dartType,
         SubtypeCheckMode.ignoringNullabilities)) {
@@ -412,9 +418,9 @@
   }
 
   void _ensureNativeTypeValid(DartType nativeType, Expression node,
-      {bool allowStructs: false, bool allowHandle: false}) {
+      {bool allowHandle: false}) {
     if (!_nativeTypeValid(nativeType,
-        allowStructs: allowStructs, allowHandle: allowHandle)) {
+        allowStructs: true, allowHandle: allowHandle)) {
       diagnosticReporter.report(
           templateFfiTypeInvalid.withArguments(
               nativeType, currentLibrary.isNonNullableByDefault),
@@ -425,11 +431,35 @@
     }
   }
 
+  void _ensureNoEmptyStructs(DartType nativeType, Expression node) {
+    // Error on structs with no fields.
+    if (nativeType is InterfaceType) {
+      final Class nativeClass = nativeType.classNode;
+      if (hierarchy.isSubclassOf(nativeClass, structClass)) {
+        if (emptyStructs.contains(nativeClass)) {
+          diagnosticReporter.report(
+              templateFfiEmptyStruct.withArguments(nativeClass.name),
+              node.fileOffset,
+              1,
+              node.location.file);
+        }
+      }
+    }
+
+    // Recurse when seeing a function type.
+    if (nativeType is FunctionType) {
+      nativeType.positionalParameters
+          .forEach((e) => _ensureNoEmptyStructs(e, node));
+      _ensureNoEmptyStructs(nativeType.returnType, node);
+    }
+  }
+
   /// The Dart type system does not enforce that NativeFunction return and
   /// parameter types are only NativeTypes, so we need to check this.
   bool _nativeTypeValid(DartType nativeType,
       {bool allowStructs: false, allowHandle: false}) {
-    return convertNativeTypeToDartType(nativeType, allowStructs, allowHandle) !=
+    return convertNativeTypeToDartType(nativeType,
+            allowStructs: allowStructs, allowHandle: allowHandle) !=
         null;
   }
 
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index 2144be8..cd97151 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -299,6 +299,16 @@
   ASSERT(!code.IsNull());
   thread->SetFfiCallbackCode(function.FfiCallbackId(), code);
 
+#ifdef TARGET_ARCH_IA32
+  // On ia32, store the stack delta that we need to use when returning.
+  const intptr_t stack_return_delta =
+      function.FfiCSignatureReturnsStruct() && CallingConventions::kUsesRet4
+          ? compiler::target::kWordSize
+          : 0;
+  thread->SetFfiCallbackStackReturn(function.FfiCallbackId(),
+                                    stack_return_delta);
+#endif
+
   uword entry_point = code.EntryPoint();
 #if !defined(DART_PRECOMPILED_RUNTIME)
   if (NativeCallbackTrampolines::Enabled()) {
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 72ce4b3..4809768 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -1673,6 +1673,7 @@
         result_location = locs->in(0);
         break;
       case Location::kRequiresFpuRegister:
+      case Location::kRequiresStackSlot:
         UNREACHABLE();
         break;
     }
@@ -3393,8 +3394,6 @@
   EmitNativeMoveArchitecture(destination, source);
 }
 
-// TODO(dartbug.com/36730): Remove this if PairLocations can be converted
-// into NativeLocations.
 void FlowGraphCompiler::EmitMoveToNative(
     const compiler::ffi::NativeLocation& dst,
     Location src_loc,
@@ -3413,8 +3412,6 @@
   }
 }
 
-// TODO(dartbug.com/36730): Remove this if PairLocations can be converted
-// into NativeLocations.
 void FlowGraphCompiler::EmitMoveFromNative(
     Location dst_loc,
     Representation dst_type,
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index c78165f..bc5a039 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -4187,6 +4187,10 @@
   __ Comment("SaveArguments");
 
   // Save the argument registers, in reverse order.
+  const auto& return_loc = marshaller_.Location(compiler::ffi::kResultIndex);
+  if (return_loc.IsPointerToMemory()) {
+    SaveArgument(compiler, return_loc.AsPointerToMemory().pointer_location());
+  }
   for (intptr_t i = marshaller_.num_args(); i-- > 0;) {
     SaveArgument(compiler, marshaller_.Location(i));
   }
@@ -4214,8 +4218,24 @@
     const auto& dst = compiler::ffi::NativeStackLocation(
         nloc.payload_type(), nloc.payload_type(), SPREG, 0);
     compiler->EmitNativeMove(dst, nloc, &temp_alloc);
+  } else if (nloc.IsPointerToMemory()) {
+    const auto& pointer_loc = nloc.AsPointerToMemory().pointer_location();
+    if (pointer_loc.IsRegisters()) {
+      const auto& regs_loc = pointer_loc.AsRegisters();
+      ASSERT(regs_loc.num_regs() == 1);
+      __ PushRegister(regs_loc.reg_at(0));
+    } else {
+      ASSERT(pointer_loc.IsStack());
+      // It's already on the stack, so we don't have to save it.
+    }
   } else {
-    UNREACHABLE();
+    ASSERT(nloc.IsMultiple());
+    const auto& multiple = nloc.AsMultiple();
+    const intptr_t num = multiple.locations().length();
+    // Save the argument registers, in reverse order.
+    for (intptr_t i = num; i-- > 0;) {
+      SaveArgument(compiler, *multiple.locations().At(i));
+    }
   }
 }
 
@@ -4522,8 +4542,12 @@
       /*old_base=*/SPREG, /*new_base=*/FPREG,
       (-kExitLinkSlotFromEntryFp + kEntryFramePadding) *
           compiler::target::kWordSize);
+  const auto& location =
+      marshaller_.NativeLocationOfNativeParameter(def_index_);
   const auto& src =
-      rebase.Rebase(marshaller_.NativeLocationOfNativeParameter(index_));
+      rebase.Rebase(location.IsPointerToMemory()
+                        ? location.AsPointerToMemory().pointer_location()
+                        : location);
   NoTemporaryAllocator no_temp;
   const Location out_loc = locs()->out(0);
   const Representation out_rep = representation();
@@ -6187,7 +6211,7 @@
   set_native_c_function(native_function);
 }
 
-#if !defined(TARGET_ARCH_ARM)
+#if !defined(TARGET_ARCH_ARM) && !defined(TARGET_ARCH_ARM64)
 
 LocationSummary* BitCastInstr::MakeLocationSummary(Zone* zone, bool opt) const {
   UNREACHABLE();
@@ -6197,13 +6221,16 @@
   UNREACHABLE();
 }
 
-#endif  // defined(TARGET_ARCH_ARM)
+#endif  // !defined(TARGET_ARCH_ARM) && !defined(TARGET_ARCH_ARM64)
 
 Representation FfiCallInstr::RequiredInputRepresentation(intptr_t idx) const {
-  if (idx == TargetAddressIndex()) {
+  if (idx < TargetAddressIndex()) {
+    return marshaller_.RepInFfiCall(idx);
+  } else if (idx == TargetAddressIndex()) {
     return kUnboxedFfiIntPtr;
   } else {
-    return marshaller_.RepInFfiCall(idx);
+    ASSERT(idx == TypedDataIndex());
+    return kTagged;
   }
 }
 
@@ -6222,51 +6249,216 @@
       LocationSummary(zone, /*num_inputs=*/InputCount(),
                       /*num_temps=*/kNumTemps, LocationSummary::kCall);
 
+  const Register temp0 = CallingConventions::kSecondNonArgumentRegister;
+  const Register temp1 = CallingConventions::kFfiAnyNonAbiRegister;
+  ASSERT(temp0 != temp1);
+  summary->set_temp(0, Location::RegisterLocation(temp0));
+  summary->set_temp(1, Location::RegisterLocation(temp1));
+
   summary->set_in(TargetAddressIndex(),
                   Location::RegisterLocation(
                       CallingConventions::kFirstNonArgumentRegister));
-  summary->set_temp(0, Location::RegisterLocation(
-                           CallingConventions::kSecondNonArgumentRegister));
-  summary->set_temp(
-      1, Location::RegisterLocation(CallingConventions::kFfiAnyNonAbiRegister));
-  summary->set_out(0, marshaller_.LocInFfiCall(compiler::ffi::kResultIndex));
-
-  for (intptr_t i = 0, n = marshaller_.num_args(); i < n; ++i) {
+  for (intptr_t i = 0, n = marshaller_.NumDefinitions(); i < n; ++i) {
     summary->set_in(i, marshaller_.LocInFfiCall(i));
   }
 
+  if (marshaller_.PassTypedData()) {
+    // The register allocator already preserves this value across the call on
+    // a stack slot, so we'll use the spilled value directly.
+    summary->set_in(TypedDataIndex(), Location::RequiresStackSlot());
+
+    // We don't care about return location, but we need to pass a register.
+    summary->set_out(
+        0, Location::RegisterLocation(CallingConventions::kReturnReg));
+  } else {
+    summary->set_out(0, marshaller_.LocInFfiCall(compiler::ffi::kResultIndex));
+  }
+
   return summary;
 }
 
 void FfiCallInstr::EmitParamMoves(FlowGraphCompiler* compiler) {
+  if (compiler::Assembler::EmittingComments()) {
+    __ Comment("EmitParamMoves");
+  }
+
   const Register saved_fp = locs()->temp(0).reg();
   const Register temp = locs()->temp(1).reg();
 
+  // Moves for return pointer.
+  const auto& return_location =
+      marshaller_.Location(compiler::ffi::kResultIndex);
+  if (return_location.IsPointerToMemory()) {
+    const auto& pointer_location =
+        return_location.AsPointerToMemory().pointer_location();
+    const auto& pointer_register =
+        pointer_location.IsRegisters()
+            ? pointer_location.AsRegisters().reg_at(0)
+            : temp;
+    __ MoveRegister(pointer_register, SPREG);
+    __ AddImmediate(pointer_register, marshaller_.PassByPointerStackOffset(
+                                          compiler::ffi::kResultIndex));
+
+    if (pointer_location.IsStack()) {
+      const auto& pointer_stack = pointer_location.AsStack();
+      __ StoreMemoryValue(pointer_register, pointer_stack.base_register(),
+                          pointer_stack.offset_in_bytes());
+    }
+  }
+
+  // Moves for arguments.
   compiler::ffi::FrameRebase rebase(zone_, /*old_base=*/FPREG,
                                     /*new_base=*/saved_fp,
                                     /*stack_delta=*/0);
-  for (intptr_t i = 0, n = NativeArgCount(); i < n; ++i) {
-    const Location origin = rebase.Rebase(locs()->in(i));
-    const Representation origin_rep = RequiredInputRepresentation(i);
-    const auto& target = marshaller_.Location(i);
-    ConstantTemporaryAllocator temp_alloc(temp);
-    if (origin.IsConstant()) {
-      compiler->EmitMoveConst(target, origin, origin_rep, &temp_alloc);
-    } else {
-      compiler->EmitMoveToNative(target, origin, origin_rep, &temp_alloc);
+  intptr_t def_index = 0;
+  for (intptr_t arg_index = 0; arg_index < marshaller_.num_args();
+       arg_index++) {
+    const intptr_t num_defs = marshaller_.NumDefinitions(arg_index);
+    const auto& arg_target = marshaller_.Location(arg_index);
+
+    // First deal with moving all individual definitions passed in to the
+    // FfiCall to the right native location based on calling convention.
+    for (intptr_t i = 0; i < num_defs; i++) {
+      const Location origin = rebase.Rebase(locs()->in(def_index));
+      const Representation origin_rep =
+          RequiredInputRepresentation(def_index) == kTagged
+              ? kUnboxedFfiIntPtr  // When arg_target.IsPointerToMemory().
+              : RequiredInputRepresentation(def_index);
+
+      // Find the native location where this individual definition should be
+      // moved to.
+      const auto& def_target =
+          arg_target.payload_type().IsPrimitive()
+              ? arg_target
+              : arg_target.IsMultiple()
+                    ? *arg_target.AsMultiple().locations()[i]
+                    : arg_target.IsPointerToMemory()
+                          ? arg_target.AsPointerToMemory().pointer_location()
+                          : /*arg_target.IsStack()*/ arg_target.Split(
+                                zone_, num_defs, i);
+
+      ConstantTemporaryAllocator temp_alloc(temp);
+      if (origin.IsConstant()) {
+        compiler->EmitMoveConst(def_target, origin, origin_rep, &temp_alloc);
+      } else {
+        compiler->EmitMoveToNative(def_target, origin, origin_rep, &temp_alloc);
+      }
+      def_index++;
     }
+
+    // Then make sure that any pointers passed through the calling convention
+    // actually have a copy of the struct.
+    // Note that the step above has already moved the pointer into the expected
+    // native location.
+    if (arg_target.IsPointerToMemory()) {
+      NoTemporaryAllocator temp_alloc;
+      const auto& pointer_loc =
+          arg_target.AsPointerToMemory().pointer_location();
+
+      // TypedData/Pointer data pointed to in temp.
+      const auto& dst = compiler::ffi::NativeRegistersLocation(
+          zone_, pointer_loc.payload_type(), pointer_loc.container_type(),
+          temp);
+      compiler->EmitNativeMove(dst, pointer_loc, &temp_alloc);
+      __ LoadField(
+          temp,
+          compiler::FieldAddress(
+              temp, compiler::target::TypedDataBase::data_field_offset()));
+
+      // Copy chuncks.
+      const intptr_t sp_offset =
+          marshaller_.PassByPointerStackOffset(arg_index);
+      // Struct size is rounded up to a multiple of target::kWordSize.
+      // This is safe because we do the same rounding when we allocate the
+      // space on the stack.
+      for (intptr_t i = 0; i < arg_target.payload_type().SizeInBytes();
+           i += compiler::target::kWordSize) {
+        __ LoadMemoryValue(TMP, temp, i);
+        __ StoreMemoryValue(TMP, SPREG, i + sp_offset);
+      }
+
+      // Store the stack address in the argument location.
+      __ MoveRegister(temp, SPREG);
+      __ AddImmediate(temp, sp_offset);
+      const auto& src = compiler::ffi::NativeRegistersLocation(
+          zone_, pointer_loc.payload_type(), pointer_loc.container_type(),
+          temp);
+      compiler->EmitNativeMove(pointer_loc, src, &temp_alloc);
+    }
+  }
+
+  if (compiler::Assembler::EmittingComments()) {
+    __ Comment("EmitParamMovesEnd");
   }
 }
 
 void FfiCallInstr::EmitReturnMoves(FlowGraphCompiler* compiler) {
-  const auto& src = marshaller_.Location(compiler::ffi::kResultIndex);
-  if (src.payload_type().IsVoid()) {
+  __ Comment("EmitReturnMoves");
+
+  const auto& returnLocation =
+      marshaller_.Location(compiler::ffi::kResultIndex);
+  if (returnLocation.payload_type().IsVoid()) {
     return;
   }
-  const Location dst_loc = locs()->out(0);
-  const Representation dst_type = representation();
+
   NoTemporaryAllocator no_temp;
-  compiler->EmitMoveFromNative(dst_loc, dst_type, src, &no_temp);
+  if (returnLocation.IsRegisters() || returnLocation.IsFpuRegisters()) {
+    const auto& src = returnLocation;
+    const Location dst_loc = locs()->out(0);
+    const Representation dst_type = representation();
+    compiler->EmitMoveFromNative(dst_loc, dst_type, src, &no_temp);
+  } else if (returnLocation.IsPointerToMemory() ||
+             returnLocation.IsMultiple()) {
+    ASSERT(returnLocation.payload_type().IsCompound());
+    ASSERT(marshaller_.PassTypedData());
+
+    const Register temp0 = TMP != kNoRegister ? TMP : locs()->temp(0).reg();
+    const Register temp1 = locs()->temp(1).reg();
+    ASSERT(temp0 != temp1);
+
+    // Get the typed data pointer which we have pinned to a stack slot.
+    const Location typed_data_loc = locs()->in(TypedDataIndex());
+    ASSERT(typed_data_loc.IsStackSlot());
+    ASSERT(typed_data_loc.base_reg() == FPREG);
+    __ LoadMemoryValue(temp0, FPREG, 0);
+    __ LoadMemoryValue(temp0, temp0, typed_data_loc.ToStackSlotOffset());
+    __ LoadField(
+        temp0,
+        compiler::FieldAddress(
+            temp0, compiler::target::TypedDataBase::data_field_offset()));
+
+    if (returnLocation.IsPointerToMemory()) {
+      // Copy blocks from the stack location to TypedData.
+      // Struct size is rounded up to a multiple of target::kWordSize.
+      // This is safe because we do the same rounding when we allocate the
+      // TypedData in IL.
+      const intptr_t sp_offset =
+          marshaller_.PassByPointerStackOffset(compiler::ffi::kResultIndex);
+      for (intptr_t i = 0; i < marshaller_.TypedDataSizeInBytes();
+           i += compiler::target::kWordSize) {
+        __ LoadMemoryValue(temp1, SPREG, i + sp_offset);
+        __ StoreMemoryValue(temp1, temp0, i);
+      }
+    } else {
+      ASSERT(returnLocation.IsMultiple());
+      // Copy to the struct from the native locations.
+      const auto& multiple =
+          marshaller_.Location(compiler::ffi::kResultIndex).AsMultiple();
+
+      int offset_in_bytes = 0;
+      for (int i = 0; i < multiple.locations().length(); i++) {
+        const auto& src = *multiple.locations().At(i);
+        const auto& dst = compiler::ffi::NativeStackLocation(
+            src.payload_type(), src.container_type(), temp0, offset_in_bytes);
+        compiler->EmitNativeMove(dst, src, &no_temp);
+        offset_in_bytes += src.payload_type().SizeInBytes();
+      }
+    }
+  } else {
+    UNREACHABLE();
+  }
+
+  __ Comment("EmitReturnMovesEnd");
 }
 
 static Location FirstArgumentLocation() {
@@ -6397,10 +6589,37 @@
 }
 
 void NativeReturnInstr::EmitReturnMoves(FlowGraphCompiler* compiler) {
-  const auto& dst = marshaller_.Location(compiler::ffi::kResultIndex);
-  if (dst.payload_type().IsVoid()) {
+  const auto& dst1 = marshaller_.Location(compiler::ffi::kResultIndex);
+  if (dst1.payload_type().IsVoid()) {
     return;
   }
+  if (dst1.IsMultiple()) {
+    Register typed_data_reg = locs()->in(0).reg();
+    // Load the data pointer out of the TypedData/Pointer.
+    __ LoadField(typed_data_reg,
+                 compiler::FieldAddress(
+                     typed_data_reg,
+                     compiler::target::TypedDataBase::data_field_offset()));
+
+    const auto& multiple = dst1.AsMultiple();
+    int offset_in_bytes = 0;
+    for (intptr_t i = 0; i < multiple.locations().length(); i++) {
+      const auto& dst = *multiple.locations().At(i);
+      ASSERT(!dst.IsRegisters() ||
+             dst.AsRegisters().reg_at(0) != typed_data_reg);
+      const auto& src = compiler::ffi::NativeStackLocation(
+          dst.payload_type(), dst.container_type(), typed_data_reg,
+          offset_in_bytes);
+      NoTemporaryAllocator no_temp;
+      compiler->EmitNativeMove(dst, src, &no_temp);
+      offset_in_bytes += dst.payload_type().SizeInBytes();
+    }
+    return;
+  }
+  const auto& dst = dst1.IsPointerToMemory()
+                        ? dst1.AsPointerToMemory().pointer_return_location()
+                        : dst1;
+
   const Location src_loc = locs()->in(0);
   const Representation src_type = RequiredInputRepresentation(0);
   NoTemporaryAllocator no_temp;
@@ -6413,14 +6632,32 @@
   const intptr_t kNumTemps = 0;
   LocationSummary* locs = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  locs->set_in(
-      0, marshaller_.LocationOfNativeParameter(compiler::ffi::kResultIndex));
+  ASSERT(marshaller_.NumReturnDefinitions() == 1);
+  const auto& native_loc = marshaller_.Location(compiler::ffi::kResultIndex);
+  const auto& native_return_loc =
+      native_loc.IsPointerToMemory()
+          ? native_loc.AsPointerToMemory().pointer_return_location()
+          : native_loc;
+  if (native_loc.IsMultiple()) {
+    // We pass in a typed data for easy copying in machine code.
+    // Can be any register which does not conflict with return registers.
+    Register typed_data_reg = CallingConventions::kSecondNonArgumentRegister;
+    ASSERT(typed_data_reg != CallingConventions::kReturnReg);
+    ASSERT(typed_data_reg != CallingConventions::kSecondReturnReg);
+    locs->set_in(0, Location::RegisterLocation(typed_data_reg));
+  } else {
+    locs->set_in(0, native_return_loc.AsLocation());
+  }
   return locs;
 }
 
 #undef Z
 
 Representation FfiCallInstr::representation() const {
+  if (marshaller_.PassTypedData()) {
+    // Don't care, we're discarding the value.
+    return kTagged;
+  }
   return marshaller_.RepInFfiCall(compiler::ffi::kResultIndex);
 }
 
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index d4160cc..e09dd09 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -2622,16 +2622,13 @@
 class NativeParameterInstr : public Definition {
  public:
   NativeParameterInstr(const compiler::ffi::CallbackMarshaller& marshaller,
-                       intptr_t index)
-      : marshaller_(marshaller), index_(index) {
-    const auto& loc = marshaller.NativeLocationOfNativeParameter(index_);
-    ASSERT(loc.IsStack() && loc.AsStack().base_register() == SPREG);
-  }
+                       intptr_t def_index)
+      : marshaller_(marshaller), def_index_(def_index) {}
 
   DECLARE_INSTRUCTION(NativeParameter)
 
   virtual Representation representation() const {
-    return marshaller_.RepInFfiCall(index_);
+    return marshaller_.RepInFfiCall(def_index_);
   }
 
   intptr_t InputCount() const { return 0; }
@@ -2655,7 +2652,7 @@
   virtual void RawSetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
 
   const compiler::ffi::CallbackMarshaller& marshaller_;
-  const intptr_t index_;
+  const intptr_t def_index_;
 
   DISALLOW_COPY_AND_ASSIGN(NativeParameterInstr);
 };
@@ -5089,7 +5086,11 @@
 // are unboxed and passed through the native calling convention. However, not
 // all dart objects can be passed as arguments. Please see the FFI documentation
 // for more details.
-// TODO(35775): Add link to the documentation when it's written.
+//
+// Arguments to FfiCallInstr:
+// - The arguments to the native call, marshalled in IL as far as possible.
+// - The argument address.
+// - A TypedData for the return value to populate in machine code (optional).
 class FfiCallInstr : public Definition {
  public:
   FfiCallInstr(Zone* zone,
@@ -5098,17 +5099,23 @@
       : Definition(deopt_id),
         zone_(zone),
         marshaller_(marshaller),
-        inputs_(marshaller.num_args() + 1) {
-    inputs_.FillWith(nullptr, 0, marshaller.num_args() + 1);
+        inputs_(marshaller.NumDefinitions() + 1 +
+                (marshaller.PassTypedData() ? 1 : 0)) {
+    inputs_.FillWith(
+        nullptr, 0,
+        marshaller.NumDefinitions() + 1 + (marshaller.PassTypedData() ? 1 : 0));
   }
 
   DECLARE_INSTRUCTION(FfiCall)
 
-  // Number of arguments to the native function.
-  intptr_t NativeArgCount() const { return InputCount() - 1; }
-
   // Input index of the function pointer to invoke.
-  intptr_t TargetAddressIndex() const { return NativeArgCount(); }
+  intptr_t TargetAddressIndex() const { return marshaller_.NumDefinitions(); }
+
+  // Input index of the typed data to populate if return value is struct.
+  intptr_t TypedDataIndex() const {
+    ASSERT(marshaller_.PassTypedData());
+    return marshaller_.NumDefinitions() + 1;
+  }
 
   virtual intptr_t InputCount() const { return inputs_.length(); }
   virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 5b646c98..999f9a5 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -1298,7 +1298,7 @@
   __ EnterDartFrame(0, /*load_pool_pointer=*/false);
 
   // Reserve space for arguments and align frame before entering C++ world.
-  __ ReserveAlignedFrameSpace(marshaller_.StackTopInBytes());
+  __ ReserveAlignedFrameSpace(marshaller_.RequiredStackSpaceInBytes());
 
   EmitParamMoves(compiler);
 
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index d103107..201633d 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -1129,7 +1129,7 @@
   __ EnterDartFrame(0, PP);
 
   // Make space for arguments and align the frame.
-  __ ReserveAlignedFrameSpace(marshaller_.StackTopInBytes());
+  __ ReserveAlignedFrameSpace(marshaller_.RequiredStackSpaceInBytes());
 
   EmitParamMoves(compiler);
 
@@ -1206,11 +1206,11 @@
 
   // The dummy return address is in LR, no need to pop it as on Intel.
 
-  // These can be anything besides the return register (R0) and THR (R26).
-  const Register vm_tag_reg = R1;
-  const Register old_exit_frame_reg = R2;
-  const Register old_exit_through_ffi_reg = R3;
-  const Register tmp = R4;
+  // These can be anything besides the return registers (R0, R1) and THR (R26).
+  const Register vm_tag_reg = R2;
+  const Register old_exit_frame_reg = R3;
+  const Register old_exit_through_ffi_reg = R4;
+  const Register tmp = R5;
 
   __ PopPair(old_exit_frame_reg, old_exit_through_ffi_reg);
 
@@ -6468,6 +6468,74 @@
   }
 }
 
+LocationSummary* BitCastInstr::MakeLocationSummary(Zone* zone, bool opt) const {
+  LocationSummary* summary =
+      new (zone) LocationSummary(zone, /*num_inputs=*/InputCount(),
+                                 /*num_temps=*/0, LocationSummary::kNoCall);
+  switch (from()) {
+    case kUnboxedInt32:
+    case kUnboxedInt64:
+      summary->set_in(0, Location::RequiresRegister());
+      break;
+    case kUnboxedFloat:
+    case kUnboxedDouble:
+      summary->set_in(0, Location::RequiresFpuRegister());
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  switch (to()) {
+    case kUnboxedInt32:
+    case kUnboxedInt64:
+      summary->set_out(0, Location::RequiresRegister());
+      break;
+    case kUnboxedFloat:
+    case kUnboxedDouble:
+      summary->set_out(0, Location::RequiresFpuRegister());
+      break;
+    default:
+      UNREACHABLE();
+  }
+  return summary;
+}
+
+void BitCastInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  switch (from()) {
+    case kUnboxedInt32: {
+      ASSERT(to() == kUnboxedFloat);
+      const Register from_reg = locs()->in(0).reg();
+      const FpuRegister to_reg = locs()->out(0).fpu_reg();
+      __ fmovsr(to_reg, from_reg);
+      break;
+    }
+    case kUnboxedFloat: {
+      ASSERT(to() == kUnboxedInt32);
+      const FpuRegister from_reg = locs()->in(0).fpu_reg();
+      const Register to_reg = locs()->out(0).reg();
+      __ fmovrs(to_reg, from_reg);
+      break;
+    }
+    case kUnboxedInt64: {
+      ASSERT(to() == kUnboxedDouble);
+
+      const Register from_reg = locs()->in(0).reg();
+      const FpuRegister to_reg = locs()->out(0).fpu_reg();
+      __ fmovdr(to_reg, from_reg);
+      break;
+    }
+    case kUnboxedDouble: {
+      ASSERT(to() == kUnboxedInt64);
+      const FpuRegister from_reg = locs()->in(0).fpu_reg();
+      const Register to_reg = locs()->out(0).reg();
+      __ fmovrd(to_reg, from_reg);
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+}
+
 LocationSummary* StopInstr::MakeLocationSummary(Zone* zone, bool opt) const {
   return new (zone) LocationSummary(zone, 0, 0, LocationSummary::kNoCall);
 }
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index d85a5f3..bd3bd78 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -338,6 +338,7 @@
   // Leave the entry frame.
   __ LeaveFrame();
 
+  // We deal with `ret 4` for structs in the JIT callback trampolines.
   __ ret();
 }
 
@@ -998,7 +999,7 @@
 
   // We need to create a dummy "exit frame". It will have a null code object.
   __ LoadObject(CODE_REG, Object::null_object());
-  __ EnterDartFrame(marshaller_.StackTopInBytes());
+  __ EnterDartFrame(marshaller_.RequiredStackSpaceInBytes());
 
   // Align frame before entering C++ world.
   if (OS::ActivationFrameAlignment() > 1) {
@@ -1035,6 +1036,16 @@
   ASSERT(temp == EBX && branch == EAX);
   __ call(temp);
 
+  // Restore the stack when a struct by value is returned into memory pointed
+  // to by a pointer that is passed into the function.
+  if (CallingConventions::kUsesRet4 &&
+      marshaller_.Location(compiler::ffi::kResultIndex).IsPointerToMemory()) {
+    // Callee uses `ret 4` instead of `ret` to return.
+    // See: https://c9x.me/x86/html/file_module_x86_id_280.html
+    // Caller does `sub esp, 4` immediately after return to balance stack.
+    __ subl(SPREG, compiler::Immediate(compiler::target::kWordSize));
+  }
+
   // The x86 calling convention requires floating point values to be returned on
   // the "floating-point stack" (aka. register ST0). We don't use the
   // floating-point stack in Dart, so we need to move the return value back into
diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc
index 6a3fc15..530f4ce 100644
--- a/runtime/vm/compiler/backend/il_printer.cc
+++ b/runtime/vm/compiler/backend/il_printer.cc
@@ -1067,11 +1067,26 @@
 void FfiCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
   f->AddString(" pointer=");
   InputAt(TargetAddressIndex())->PrintTo(f);
-  for (intptr_t i = 0, n = InputCount(); i < n - 1; ++i) {
+  if (marshaller_.PassTypedData()) {
+    f->AddString(", typed_data=");
+    InputAt(TypedDataIndex())->PrintTo(f);
+  }
+  intptr_t def_index = 0;
+  for (intptr_t arg_index = 0; arg_index < marshaller_.num_args();
+       arg_index++) {
+    const auto& arg_location = marshaller_.Location(arg_index);
+    const bool is_compound = arg_location.container_type().IsCompound();
+    const intptr_t num_defs = marshaller_.NumDefinitions(arg_index);
     f->AddString(", ");
-    InputAt(i)->PrintTo(f);
+    if (is_compound) f->AddString("(");
+    for (intptr_t i = 0; i < num_defs; i++) {
+      InputAt(def_index)->PrintTo(f);
+      if ((i + 1) < num_defs) f->AddString(", ");
+      def_index++;
+    }
+    if (is_compound) f->AddString(")");
     f->AddString(" (@");
-    marshaller_.Location(i).PrintTo(f);
+    arg_location.PrintTo(f);
     f->AddString(")");
   }
 }
@@ -1093,10 +1108,10 @@
 
 void NativeParameterInstr::PrintOperandsTo(BaseTextBuffer* f) const {
   // Where the calling convention puts it.
-  marshaller_.Location(index_).PrintTo(f);
+  marshaller_.Location(marshaller_.ArgumentIndex(def_index_)).PrintTo(f);
   f->AddString(" at ");
   // Where the arguments are when pushed on the stack.
-  marshaller_.NativeLocationOfNativeParameter(index_).PrintTo(f);
+  marshaller_.NativeLocationOfNativeParameter(def_index_).PrintTo(f);
 }
 
 void CatchBlockEntryInstr::PrintTo(BaseTextBuffer* f) const {
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 6da1cd6..01faa99 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -1060,7 +1060,7 @@
   // but have a null code object.
   __ LoadObject(CODE_REG, Object::null_object());
   __ set_constant_pool_allowed(false);
-  __ EnterDartFrame(marshaller_.StackTopInBytes(), PP);
+  __ EnterDartFrame(marshaller_.RequiredStackSpaceInBytes(), PP);
 
   // Align frame before entering C++ world.
   if (OS::ActivationFrameAlignment() > 1) {
diff --git a/runtime/vm/compiler/backend/linearscan.cc b/runtime/vm/compiler/backend/linearscan.cc
index 4070e5d..f87c06e 100644
--- a/runtime/vm/compiler/backend/linearscan.cc
+++ b/runtime/vm/compiler/backend/linearscan.cc
@@ -1370,7 +1370,7 @@
     }
   }
 
-// Block all allocatable registers for calls.
+  // Block all allocatable registers for calls.
   if (locs->always_calls() && !locs->callee_safe_call()) {
     // Expected shape of live range:
     //
@@ -1407,7 +1407,8 @@
                pair->At(1).policy() == Location::kAny);
       } else {
         ASSERT(!locs->in(j).IsUnallocated() ||
-               locs->in(j).policy() == Location::kAny);
+               locs->in(j).policy() == Location::kAny ||
+               locs->in(j).policy() == Location::kRequiresStackSlot);
       }
     }
 
diff --git a/runtime/vm/compiler/backend/locations.cc b/runtime/vm/compiler/backend/locations.cc
index d31957c..858150d 100644
--- a/runtime/vm/compiler/backend/locations.cc
+++ b/runtime/vm/compiler/backend/locations.cc
@@ -155,7 +155,8 @@
   // restrictions.
   if (always_calls()) {
     if (loc.IsUnallocated()) {
-      ASSERT(loc.policy() == Location::kAny);
+      ASSERT(loc.policy() == Location::kAny ||
+             loc.policy() == Location::kRequiresStackSlot);
     } else if (loc.IsPairLocation()) {
       ASSERT(!loc.AsPairLocation()->At(0).IsUnallocated() ||
              loc.AsPairLocation()->At(0).policy() == Location::kAny);
@@ -280,6 +281,8 @@
           return "R";
         case kRequiresFpuRegister:
           return "DR";
+        case kRequiresStackSlot:
+          return "RS";
         case kWritableRegister:
           return "WR";
         case kSameAsFirstInput:
diff --git a/runtime/vm/compiler/backend/locations.h b/runtime/vm/compiler/backend/locations.h
index 942e10a..ea708e4 100644
--- a/runtime/vm/compiler/backend/locations.h
+++ b/runtime/vm/compiler/backend/locations.h
@@ -238,6 +238,7 @@
     kPrefersRegister,
     kRequiresRegister,
     kRequiresFpuRegister,
+    kRequiresStackSlot,
     kWritableRegister,
     kSameAsFirstInput,
   };
@@ -265,6 +266,10 @@
     return UnallocatedLocation(kRequiresFpuRegister);
   }
 
+  static Location RequiresStackSlot() {
+    return UnallocatedLocation(kRequiresStackSlot);
+  }
+
   static Location WritableRegister() {
     return UnallocatedLocation(kWritableRegister);
   }
diff --git a/runtime/vm/compiler/ffi/callback.cc b/runtime/vm/compiler/ffi/callback.cc
index 8d1fe95..e5a4782 100644
--- a/runtime/vm/compiler/ffi/callback.cc
+++ b/runtime/vm/compiler/ffi/callback.cc
@@ -50,9 +50,6 @@
   //
   // Exceptional return values currently cannot be pointers because we don't
   // have constant pointers.
-  //
-  // TODO(36730): We'll need to extend this when we support passing/returning
-  // structs by value.
   ASSERT(exceptional_return.IsNull() || exceptional_return.IsNumber());
   if (!exceptional_return.IsSmi() && exceptional_return.IsNew()) {
     function.SetFfiCallbackExceptionalReturn(Instance::Handle(
diff --git a/runtime/vm/compiler/ffi/marshaller.cc b/runtime/vm/compiler/ffi/marshaller.cc
index 6620468..ecf1994 100644
--- a/runtime/vm/compiler/ffi/marshaller.cc
+++ b/runtime/vm/compiler/ffi/marshaller.cc
@@ -75,11 +75,224 @@
   return dart_signature_.FfiCSignatureContainsHandles();
 }
 
-Location CallMarshaller::LocInFfiCall(intptr_t arg_index) const {
-  if (arg_index == kResultIndex) {
-    return Location(arg_index).AsLocation();
+intptr_t BaseMarshaller::NumDefinitions() const {
+  intptr_t total = 0;
+  for (intptr_t i = 0; i < num_args(); i++) {
+    total += NumDefinitions(i);
+  }
+  return total;
+}
+
+intptr_t BaseMarshaller::NumDefinitions(intptr_t arg_index) const {
+  if (ArgumentIndexIsReturn(arg_index)) {
+    return NumReturnDefinitions();
   }
 
+  const auto& loc = Location(arg_index);
+  const auto& type = loc.payload_type();
+
+  if (type.IsPrimitive()) {
+    // All non-struct arguments are 1 definition in IL. Even 64 bit values
+    // on 32 bit architectures.
+    return 1;
+  }
+
+  ASSERT(type.IsCompound());
+  if (loc.IsMultiple()) {
+    // One IL definition for every nested location.
+    const auto& multiple = loc.AsMultiple();
+    return multiple.locations().length();
+  }
+
+  if (loc.IsPointerToMemory()) {
+    // For FFI calls, pass in TypedDataBase (1 IL definition) in IL, and copy
+    // contents to stack and pass pointer in right location in MC.
+    // For FFI callbacks, get the pointer in a NativeParameter and construct
+    // the TypedDataBase in IL.
+    return 1;
+  }
+
+  ASSERT(loc.IsStack());
+  // For stack, word size definitions in IL. In FFI calls passed in to the
+  // native call, in FFI callbacks read in separate NativeParams.
+  const intptr_t size_in_bytes = type.SizeInBytes();
+  const intptr_t num_defs =
+      Utils::RoundUp(size_in_bytes, compiler::target::kWordSize) /
+      compiler::target::kWordSize;
+  return num_defs;
+}
+
+intptr_t BaseMarshaller::NumReturnDefinitions() const {
+  // For FFI calls we always have 1 definition, because the IL instruction can
+  // only be 1 definition. We pass in a TypedDataBase in IL and fill it in
+  // machine code.
+  //
+  // For FFI callbacks we always have 1 definition. If it's a struct and the
+  // native ABI is passing a pointer, we copy to it in IL. If it's a multiple
+  // locations return value we copy the value in machine code because some
+  // native locations cannot be expressed in IL in Location.
+  return 1;
+}
+
+bool BaseMarshaller::ArgumentIndexIsReturn(intptr_t arg_index) const {
+  ASSERT(arg_index == kResultIndex || arg_index >= 0);
+  return arg_index == kResultIndex;
+}
+
+// Definitions in return value count down.
+bool BaseMarshaller::DefinitionIndexIsReturn(intptr_t def_index_global) const {
+  return def_index_global <= kResultIndex;
+}
+
+intptr_t BaseMarshaller::ArgumentIndex(intptr_t def_index_global) const {
+  if (DefinitionIndexIsReturn(def_index_global)) {
+    const intptr_t def = DefinitionInArgument(def_index_global, kResultIndex);
+    ASSERT(def < NumReturnDefinitions());
+    return kResultIndex;
+  }
+  ASSERT(def_index_global < NumDefinitions());
+  intptr_t defs = 0;
+  intptr_t arg_index = 0;
+  for (; arg_index < num_args(); arg_index++) {
+    defs += NumDefinitions(arg_index);
+    if (defs > def_index_global) {
+      return arg_index;
+    }
+  }
+  UNREACHABLE();
+}
+
+intptr_t BaseMarshaller::FirstDefinitionIndex(intptr_t arg_index) const {
+  if (arg_index <= kResultIndex) {
+    return kResultIndex;
+  }
+  ASSERT(arg_index < num_args());
+  intptr_t num_defs = 0;
+  for (intptr_t i = 0; i < arg_index; i++) {
+    num_defs += NumDefinitions(i);
+  }
+  return num_defs;
+}
+
+intptr_t BaseMarshaller::DefinitionInArgument(intptr_t def_index_global,
+                                              intptr_t arg_index) const {
+  if (ArgumentIndexIsReturn(arg_index)) {
+    // Counting down for return definitions.
+    const intptr_t def = kResultIndex - def_index_global;
+    ASSERT(def < NumReturnDefinitions());
+    return def;
+  } else {
+    // Counting up for arguments in consecutive order.
+    const intptr_t def = def_index_global - FirstDefinitionIndex(arg_index);
+    ASSERT(def < NumDefinitions());
+    return def;
+  }
+}
+
+intptr_t BaseMarshaller::DefinitionIndex(intptr_t def_index_in_arg,
+                                         intptr_t arg_index) const {
+  ASSERT(def_index_in_arg < NumDefinitions(arg_index));
+  if (ArgumentIndexIsReturn(arg_index)) {
+    return kResultIndex - def_index_in_arg;
+  } else {
+    return FirstDefinitionIndex(arg_index) + def_index_in_arg;
+  }
+}
+
+static Representation SelectRepresentationInIL(Zone* zone,
+                                               const NativeLocation& location) {
+  if (location.container_type().IsInt() && location.payload_type().IsFloat()) {
+    // IL can only pass integers to integer Locations, so pass as integer if
+    // the Location requires it to be an integer.
+    return location.container_type().AsRepresentationOverApprox(zone);
+  }
+  // Representations do not support 8 or 16 bit ints, over approximate to 32
+  // bits.
+  return location.payload_type().AsRepresentationOverApprox(zone);
+}
+
+// Implemented partially in BaseMarshaller because most Representations are
+// the same in Calls and Callbacks.
+Representation BaseMarshaller::RepInFfiCall(intptr_t def_index_global) const {
+  intptr_t arg_index = ArgumentIndex(def_index_global);
+  const auto& location = Location(arg_index);
+
+  if (location.container_type().IsPrimitive()) {
+    return SelectRepresentationInIL(zone_, location);
+  }
+  ASSERT(location.container_type().IsCompound());
+
+  if (location.IsStack()) {
+    // Split the struct in architecture size chunks.
+    return compiler::target::kWordSize == 8 ? Representation::kUnboxedInt64
+                                            : Representation::kUnboxedInt32;
+  }
+
+  if (location.IsMultiple()) {
+    const intptr_t def_index_in_arg =
+        DefinitionInArgument(def_index_global, arg_index);
+    const auto& def_loc =
+        *(location.AsMultiple().locations()[def_index_in_arg]);
+    return SelectRepresentationInIL(zone_, def_loc);
+  }
+
+  ASSERT(location.IsPointerToMemory());
+  UNREACHABLE();  // Implemented in subclasses.
+}
+
+Representation CallMarshaller::RepInFfiCall(intptr_t def_index_global) const {
+  intptr_t arg_index = ArgumentIndex(def_index_global);
+  const auto& location = Location(arg_index);
+  if (location.IsPointerToMemory()) {
+    if (ArgumentIndexIsReturn(arg_index)) {
+      // The IL type is the unboxed pointer.
+      const auto& pointer_location = location.AsPointerToMemory();
+      const auto& rep = pointer_location.pointer_location().payload_type();
+      ASSERT(rep.Equals(
+          pointer_location.pointer_return_location().payload_type()));
+      return rep.AsRepresentation();
+    } else {
+      // We're passing Pointer/TypedData object, the GC might move TypedData so
+      // we can't load the address from it eagerly.
+      return kTagged;
+    }
+  }
+  return BaseMarshaller::RepInFfiCall(def_index_global);
+}
+
+Representation CallbackMarshaller::RepInFfiCall(
+    intptr_t def_index_global) const {
+  intptr_t arg_index = ArgumentIndex(def_index_global);
+  const auto& location = Location(arg_index);
+  if (location.IsPointerToMemory()) {
+    // The IL type is the unboxed pointer, and FFI callback return. In the
+    // latter we've already copied the data into the result location in IL.
+    const auto& pointer_location = location.AsPointerToMemory();
+    const auto& rep = pointer_location.pointer_location().payload_type();
+    ASSERT(
+        rep.Equals(pointer_location.pointer_return_location().payload_type()));
+    return rep.AsRepresentation();
+  }
+  if (ArgumentIndexIsReturn(arg_index) && location.IsMultiple()) {
+    // We're passing a TypedData.
+    return Representation::kTagged;
+  }
+  return BaseMarshaller::RepInFfiCall(def_index_global);
+}
+
+void BaseMarshaller::RepsInFfiCall(intptr_t arg_index,
+                                   GrowableArray<Representation>* out) const {
+  const intptr_t num_definitions = NumDefinitions(arg_index);
+  const intptr_t first_def = FirstDefinitionIndex(arg_index);
+  for (int i = 0; i < num_definitions; i++) {
+    out->Add(RepInFfiCall(first_def + i));
+  }
+}
+
+// Helper method for `LocInFfiCall` to turn a stack location into either any
+// location or a pair of two any locations.
+static Location ConvertToAnyLocation(const NativeStackLocation& loc,
+                                     Representation rep_in_ffi_call) {
   // Floating point values are never split: they are either in a single "FPU"
   // register or a contiguous 64-bit slot on the stack. Unboxed 64-bit integer
   // values, in contrast, can be split between any two registers on a 32-bit
@@ -90,33 +303,149 @@
   // convention is concerned. However, the representation of these arguments
   // are set to kUnboxedInt32 or kUnboxedInt64 already, so we don't have to
   // account for that here.
-  const bool is_atomic = RepInFfiCall(arg_index) == kUnboxedDouble ||
-                         RepInFfiCall(arg_index) == kUnboxedFloat;
+  const bool is_atomic =
+      rep_in_ffi_call == kUnboxedDouble || rep_in_ffi_call == kUnboxedFloat;
 
-  const NativeLocation& loc = this->Location(arg_index);
-  // Don't pin stack locations, they need to be moved anyway.
-  if (loc.IsStack()) {
-    if (loc.payload_type().SizeInBytes() == 2 * compiler::target::kWordSize &&
-        !is_atomic) {
-      return Location::Pair(Location::Any(), Location::Any());
-    }
-    return Location::Any();
+  if (loc.payload_type().IsPrimitive() &&
+      loc.payload_type().SizeInBytes() == 2 * compiler::target::kWordSize &&
+      !is_atomic) {
+    return Location::Pair(Location::Any(), Location::Any());
   }
+  return Location::Any();
+}
 
+static Location SelectFpuLocationInIL(Zone* zone,
+                                      const NativeLocation& location) {
+  ASSERT((location.IsFpuRegisters()));
 #if defined(TARGET_ARCH_ARM)
   // Only pin FPU register if it is the lowest bits.
-  if (loc.IsFpuRegisters()) {
-    const auto& fpu_loc = loc.AsFpuRegisters();
-    if (fpu_loc.IsLowestBits()) {
-      return fpu_loc.WidenToQFpuRegister(zone_).AsLocation();
-    }
-    return Location::Any();
+  const auto& fpu_loc = location.AsFpuRegisters();
+  if (fpu_loc.IsLowestBits()) {
+    return fpu_loc.WidenToQFpuRegister(zone).AsLocation();
   }
+  return Location::Any();
 #endif  // defined(TARGET_ARCH_ARM)
 
+  return location.AsLocation();
+}
+
+Location CallMarshaller::LocInFfiCall(intptr_t def_index_global) const {
+  const intptr_t arg_index = ArgumentIndex(def_index_global);
+  const NativeLocation& loc = this->Location(arg_index);
+
+  if (ArgumentIndexIsReturn(arg_index)) {
+    const intptr_t def = kResultIndex - def_index_global;
+    if (loc.IsMultiple()) {
+      ASSERT(loc.AsMultiple().locations()[def]->IsExpressibleAsLocation());
+      return loc.AsMultiple().locations()[def]->AsLocation();
+    }
+
+    if (loc.IsPointerToMemory()) {
+      // No location at all, because we store into TypedData passed to the
+      // FfiCall instruction. But we have to supply a location.
+      return Location::RegisterLocation(CallingConventions::kReturnReg);
+    }
+
+    return loc.AsLocation();
+  }
+
+  if (loc.IsMultiple()) {
+    const intptr_t def_index_in_arg =
+        def_index_global - FirstDefinitionIndex(arg_index);
+    const auto& def_loc = *(loc.AsMultiple().locations()[def_index_in_arg]);
+    if (def_loc.IsStack()) {
+      // Don't pin stack locations, they need to be moved anyway.
+      return ConvertToAnyLocation(def_loc.AsStack(),
+                                  RepInFfiCall(def_index_global));
+    }
+
+    if (def_loc.IsFpuRegisters()) {
+      return SelectFpuLocationInIL(zone_, def_loc);
+    }
+
+    return def_loc.AsLocation();
+  }
+
+  if (loc.IsPointerToMemory()) {
+    const auto& pointer_location = loc.AsPointerToMemory().pointer_location();
+    if (pointer_location.IsStack()) {
+      // Don't pin stack locations, they need to be moved anyway.
+      return ConvertToAnyLocation(pointer_location.AsStack(),
+                                  RepInFfiCall(def_index_global));
+    }
+    return pointer_location.AsLocation();
+  }
+
+  if (loc.IsStack()) {
+    return ConvertToAnyLocation(loc.AsStack(), RepInFfiCall(def_index_global));
+  }
+
+  if (loc.IsFpuRegisters()) {
+    return SelectFpuLocationInIL(zone_, loc);
+  }
+
+  ASSERT(loc.IsRegisters());
   return loc.AsLocation();
 }
 
+bool CallMarshaller::PassTypedData() const {
+  return IsStruct(compiler::ffi::kResultIndex);
+}
+
+intptr_t CallMarshaller::TypedDataSizeInBytes() const {
+  ASSERT(PassTypedData());
+  return Utils::RoundUp(
+      Location(compiler::ffi::kResultIndex).payload_type().SizeInBytes(),
+      compiler::target::kWordSize);
+}
+
+// Const to be able to look up the `RequiredStackSpaceInBytes` in
+// `PassByPointerStackOffset`.
+const intptr_t kAfterLastArgumentIndex = kIntptrMax;
+
+intptr_t CallMarshaller::PassByPointerStackOffset(intptr_t arg_index) const {
+  ASSERT(arg_index == kResultIndex ||
+         (arg_index >= 0 && arg_index < num_args()) ||
+         arg_index == kAfterLastArgumentIndex);
+
+  intptr_t stack_offset = 0;
+
+  // First the native arguments are on the stack.
+  // This is governed by the native ABI, the rest we can chose freely.
+  stack_offset += native_calling_convention_.StackTopInBytes();
+  stack_offset = Utils::RoundUp(stack_offset, compiler::target::kWordSize);
+  if (arg_index == kResultIndex) {
+    return stack_offset;
+  }
+
+  // Then save space for the result.
+  const auto& result_location = Location(compiler::ffi::kResultIndex);
+  if (result_location.IsPointerToMemory()) {
+    stack_offset += result_location.payload_type().SizeInBytes();
+    stack_offset = Utils::RoundUp(stack_offset, compiler::target::kWordSize);
+  }
+
+  // And finally put the arguments on the stack that are passed by pointer.
+  for (int i = 0; i < num_args(); i++) {
+    if (arg_index == i) {
+      return stack_offset;
+    }
+    const auto& arg_location = Location(i);
+    if (arg_location.IsPointerToMemory()) {
+      stack_offset += arg_location.payload_type().SizeInBytes();
+      stack_offset = Utils::RoundUp(stack_offset, compiler::target::kWordSize);
+    }
+  }
+
+  // The total stack space we need.
+  ASSERT(arg_index == kAfterLastArgumentIndex);
+  return stack_offset;
+}
+
+intptr_t CallMarshaller::RequiredStackSpaceInBytes() const {
+  return PassByPointerStackOffset(kAfterLastArgumentIndex);
+}
+
 // This classes translates the ABI location of arguments into the locations they
 // will inhabit after entry-frame setup in the invocation of a native callback.
 //
@@ -133,15 +462,26 @@
  public:
   static NativeLocations& TranslateArgumentLocations(
       Zone* zone,
-      const NativeLocations& arg_locs) {
-    auto& pushed_locs = *(new (zone) NativeLocations(arg_locs.length()));
+      const NativeLocations& argument_locations,
+      const NativeLocation& return_loc) {
+    const bool treat_return_loc = return_loc.IsPointerToMemory();
+
+    auto& pushed_locs = *(new (zone) NativeLocations(
+        argument_locations.length() + (treat_return_loc ? 1 : 0)));
 
     CallbackArgumentTranslator translator;
-    for (intptr_t i = 0, n = arg_locs.length(); i < n; i++) {
-      translator.AllocateArgument(*arg_locs[i]);
+    for (intptr_t i = 0, n = argument_locations.length(); i < n; i++) {
+      translator.AllocateArgument(*argument_locations[i]);
     }
-    for (intptr_t i = 0, n = arg_locs.length(); i < n; ++i) {
-      pushed_locs.Add(&translator.TranslateArgument(zone, *arg_locs[i]));
+    if (treat_return_loc) {
+      translator.AllocateArgument(return_loc);
+    }
+    for (intptr_t i = 0, n = argument_locations.length(); i < n; ++i) {
+      pushed_locs.Add(
+          &translator.TranslateArgument(zone, *argument_locations[i]));
+    }
+    if (treat_return_loc) {
+      pushed_locs.Add(&translator.TranslateArgument(zone, return_loc));
     }
 
     return pushed_locs;
@@ -155,8 +495,16 @@
       argument_slots_required_ += arg.AsRegisters().num_regs();
     } else if (arg.IsFpuRegisters()) {
       argument_slots_required_ += 8 / target::kWordSize;
+    } else if (arg.IsPointerToMemory()) {
+      if (arg.AsPointerToMemory().pointer_location().IsRegisters()) {
+        argument_slots_required_ += 1;
+      }
     } else {
-      UNREACHABLE();
+      ASSERT(arg.IsMultiple());
+      const auto& multiple = arg.AsMultiple();
+      for (intptr_t i = 0; i < multiple.locations().length(); i++) {
+        AllocateArgument(*multiple.locations().At(i));
+      }
     }
   }
 
@@ -192,12 +540,33 @@
       return result;
     }
 
-    ASSERT(arg.IsFpuRegisters());
-    const auto& result = *new (zone) NativeStackLocation(
-        arg.payload_type(), arg.container_type(), SPREG,
-        argument_slots_used_ * compiler::target::kWordSize);
-    argument_slots_used_ += 8 / target::kWordSize;
-    return result;
+    if (arg.IsFpuRegisters()) {
+      const auto& result = *new (zone) NativeStackLocation(
+          arg.payload_type(), arg.container_type(), SPREG,
+          argument_slots_used_ * compiler::target::kWordSize);
+      argument_slots_used_ += 8 / target::kWordSize;
+      return result;
+    }
+
+    if (arg.IsPointerToMemory()) {
+      const auto& pointer_loc = arg.AsPointerToMemory().pointer_location();
+      const auto& pointer_ret_loc =
+          arg.AsPointerToMemory().pointer_return_location();
+      const auto& pointer_translated = TranslateArgument(zone, pointer_loc);
+      return *new (zone) PointerToMemoryLocation(
+          pointer_translated, pointer_ret_loc, arg.payload_type().AsCompound());
+    }
+
+    ASSERT(arg.IsMultiple());
+    const auto& multiple = arg.AsMultiple();
+    NativeLocations& multiple_locations =
+        *new (zone) NativeLocations(multiple.locations().length());
+    for (intptr_t i = 0; i < multiple.locations().length(); i++) {
+      multiple_locations.Add(
+          &TranslateArgument(zone, *multiple.locations().At(i)));
+    }
+    return *new (zone) MultipleNativeLocations(
+        multiple.payload_type().AsCompound(), multiple_locations);
   }
 
   intptr_t argument_slots_used_ = 0;
@@ -209,7 +578,46 @@
     : BaseMarshaller(zone, dart_signature),
       callback_locs_(CallbackArgumentTranslator::TranslateArgumentLocations(
           zone_,
-          native_calling_convention_.argument_locations())) {}
+          native_calling_convention_.argument_locations(),
+          native_calling_convention_.return_location())) {}
+
+const NativeLocation& CallbackMarshaller::NativeLocationOfNativeParameter(
+    intptr_t def_index) const {
+  const intptr_t arg_index = ArgumentIndex(def_index);
+  if (arg_index == kResultIndex) {
+    const auto& result_loc = Location(arg_index);
+    if (result_loc.IsPointerToMemory()) {
+      // If it's a pointer we return it in the last.
+      return *callback_locs_.At(callback_locs_.length() - 1);
+    }
+    // The other return types are not translated.
+    return result_loc;
+  }
+
+  // Check that we only have stack arguments.
+  const auto& loc = *callback_locs_.At(arg_index);
+  ASSERT(loc.IsStack() || loc.IsPointerToMemory() || loc.IsMultiple());
+  if (loc.IsStack()) {
+    ASSERT(loc.AsStack().base_register() == SPREG);
+    if (loc.payload_type().IsPrimitive()) {
+      return loc;
+    }
+    const intptr_t index = DefinitionInArgument(def_index, arg_index);
+    const intptr_t count = NumDefinitions(arg_index);
+    return loc.Split(zone_, count, index);
+  } else if (loc.IsPointerToMemory()) {
+    const auto& pointer_loc = loc.AsPointerToMemory().pointer_location();
+    ASSERT(pointer_loc.IsStack() &&
+           pointer_loc.AsStack().base_register() == SPREG);
+    return loc;
+  }
+  const auto& multiple = loc.AsMultiple();
+  const intptr_t index = DefinitionInArgument(def_index, arg_index);
+  const auto& multi_loc = *multiple.locations().At(index);
+  ASSERT(multi_loc.IsStack() && multi_loc.AsStack().base_register() == SPREG);
+  return multi_loc;
+}
+
 }  // namespace ffi
 
 }  // namespace compiler
diff --git a/runtime/vm/compiler/ffi/marshaller.h b/runtime/vm/compiler/ffi/marshaller.h
index be567b6..e8306c0 100644
--- a/runtime/vm/compiler/ffi/marshaller.h
+++ b/runtime/vm/compiler/ffi/marshaller.h
@@ -39,9 +39,27 @@
     return native_calling_convention_.argument_locations().length();
   }
 
-  intptr_t StackTopInBytes() const {
-    return native_calling_convention_.StackTopInBytes();
-  }
+  // Number of definitions passed to FfiCall, number of NativeParams, or number
+  // of definitions passed to NativeReturn in IL.
+  //
+  // All non-struct values have 1 definition, struct values can have either 1
+  // or multiple definitions. If a struct has multiple definitions, they either
+  // correspond to the number of native locations in the native ABI or to word-
+  // sized chunks.
+  //
+  // `arg_index` is the index of an argument.
+  // `def_index_in_argument` is the definition in one argument.
+  // `def_index_global` is the index of the definition in all arguments.
+  intptr_t NumDefinitions() const;
+  intptr_t NumDefinitions(intptr_t arg_index) const;
+  intptr_t NumReturnDefinitions() const;
+  bool ArgumentIndexIsReturn(intptr_t arg_index) const;
+  bool DefinitionIndexIsReturn(intptr_t def_index_global) const;
+  intptr_t ArgumentIndex(intptr_t def_index_global) const;
+  intptr_t FirstDefinitionIndex(intptr_t arg_index) const;
+  intptr_t DefinitionInArgument(intptr_t def_index_global,
+                                intptr_t arg_index) const;
+  intptr_t DefinitionIndex(intptr_t def_index_in_arg, intptr_t arg_index) const;
 
   // The location of the argument at `arg_index`.
   const NativeLocation& Location(intptr_t arg_index) const {
@@ -53,20 +71,18 @@
 
   // Unboxed representation on how the value is passed or received from regular
   // Dart code.
+  //
+  // Implemented in BaseMarshaller because most Representations are the same
+  // in Calls and Callbacks.
   Representation RepInDart(intptr_t arg_index) const {
     return Location(arg_index).payload_type().AsRepresentationOverApprox(zone_);
   }
 
   // Representation on how the value is passed to or recieved from the FfiCall
   // instruction or StaticCall, NativeParameter, and NativeReturn instructions.
-  Representation RepInFfiCall(intptr_t arg_index) const {
-    if (Location(arg_index).container_type().IsInt() &&
-        Location(arg_index).payload_type().IsFloat()) {
-      return Location(arg_index).container_type().AsRepresentationOverApprox(
-          zone_);
-    }
-    return Location(arg_index).payload_type().AsRepresentationOverApprox(zone_);
-  }
+  virtual Representation RepInFfiCall(intptr_t def_index_global) const;
+  void RepsInFfiCall(intptr_t arg_index,
+                     GrowableArray<Representation>* out) const;
 
   // Bitcasting floats to ints, only required in SoftFP.
   bool RequiresBitCast(intptr_t index) const {
@@ -94,6 +110,12 @@
            kFfiHandleCid;
   }
 
+  bool IsStruct(intptr_t arg_index) const {
+    const auto& type = AbstractType::Handle(zone_, CType(arg_index));
+    const bool predefined = IsFfiTypeClassId(type.type_class_id());
+    return !predefined;
+  }
+
   // Treated as a null constant in Dart.
   bool IsVoid(intptr_t arg_index) const {
     return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
@@ -122,7 +144,24 @@
   CallMarshaller(Zone* zone, const Function& dart_signature)
       : BaseMarshaller(zone, dart_signature) {}
 
-  dart::Location LocInFfiCall(intptr_t arg_index) const;
+  virtual Representation RepInFfiCall(intptr_t def_index_global) const;
+
+  // The location of the inputs to the IL FfiCall instruction.
+  dart::Location LocInFfiCall(intptr_t def_index_global) const;
+
+  // Allocate a TypedData before the FfiCall and pass it in to the FfiCall so
+  // that it can be populated in assembly.
+  bool PassTypedData() const;
+  intptr_t TypedDataSizeInBytes() const;
+
+  // We allocate space for PointerToMemory arguments and PointerToMemory return
+  // locations on the stack. This is faster than allocation ExternalTypedData.
+  // Normal TypedData is not an option, as these might be relocated by GC
+  // during FFI calls.
+  intptr_t PassByPointerStackOffset(intptr_t arg_index) const;
+
+  // The total amount of stack space required for FFI trampolines.
+  intptr_t RequiredStackSpaceInBytes() const;
 
  protected:
   ~CallMarshaller() {}
@@ -132,19 +171,19 @@
  public:
   CallbackMarshaller(Zone* zone, const Function& dart_signature);
 
-  // All parameters are saved on stack to do safe-point transition.
-  const NativeLocation& NativeLocationOfNativeParameter(
-      intptr_t arg_index) const {
-    if (arg_index == kResultIndex) {
-      // No moving around of result.
-      return Location(arg_index);
-    }
-    return *callback_locs_.At(arg_index);
-  }
+  virtual Representation RepInFfiCall(intptr_t def_index_global) const;
 
   // All parameters are saved on stack to do safe-point transition.
-  dart::Location LocationOfNativeParameter(intptr_t arg_index) const {
-    return NativeLocationOfNativeParameter(arg_index).AsLocation();
+  const NativeLocation& NativeLocationOfNativeParameter(
+      intptr_t def_index) const;
+
+  // All parameters are saved on stack to do safe-point transition.
+  dart::Location LocationOfNativeParameter(intptr_t def_index) const {
+    const auto& native_loc = NativeLocationOfNativeParameter(def_index);
+    if (native_loc.IsPointerToMemory()) {
+      return native_loc.AsPointerToMemory().pointer_location().AsLocation();
+    }
+    return native_loc.AsLocation();
   }
 
  protected:
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index d577091..7b3e6a0 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -557,7 +557,7 @@
     dispatch += Constant(offsets);
     dispatch += LoadLocal(scopes()->switch_variable);
 
-    // Ideally this would just be LoadIndexedTypedData(kTypedDataInt32ArrayCid),
+    // Ideally this would just be LoadIndexed(kTypedDataInt32ArrayCid),
     // but that doesn't work in unoptimised code.
     // The optimiser will turn this into that in any case.
     dispatch += InstanceCall(TokenPosition::kNoSource, Symbols::IndexToken(),
@@ -2662,7 +2662,10 @@
 
 Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) {
   const intptr_t offset = ReaderOffset() - 1;     // Include the tag.
-  ReadFlags();                                    // read flags.
+
+  const uint8_t flags = ReadFlags();  // read flags.
+  const bool is_invariant = (flags & kMethodInvocationFlagInvariant) != 0;
+
   const TokenPosition position = ReadPosition();  // read position.
   if (p != NULL) *p = position;
 
@@ -2676,7 +2679,7 @@
   const Tag receiver_tag = PeekTag();  // peek tag for receiver.
 
   bool is_unchecked_closure_call = false;
-  bool is_unchecked_call = result_type.IsSkipCheck();
+  bool is_unchecked_call = is_invariant || result_type.IsSkipCheck();
   if (call_site_attributes.receiver_type != nullptr) {
     if (call_site_attributes.receiver_type->IsFunctionType()) {
       AlternativeReadingScope alt(&reader_);
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc
index 80ddd91..a688d7c 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc
@@ -247,4 +247,45 @@
   EXPECT(String::Cast(store3->value()->BoundConstant()).Equals("cd"));
 }
 
+ISOLATE_UNIT_TEST_CASE(StreamingFlowGraphBuilder_InvariantFlagInListLiterals) {
+  const char* kScript = R"(
+    test() {
+      return [...[], 42];
+    }
+  )";
+
+  const auto& root_library = Library::Handle(LoadTestScript(kScript));
+  const auto& function = Function::Handle(GetFunction(root_library, "test"));
+
+  Invoke(root_library, "test");
+
+  TestPipeline pipeline(function, CompilerPass::kJIT);
+  FlowGraph* flow_graph = pipeline.RunPasses({
+      CompilerPass::kComputeSSA,
+  });
+
+  auto entry = flow_graph->graph_entry()->normal_entry();
+  EXPECT(entry != nullptr);
+
+  InstanceCallInstr* call_add = nullptr;
+
+  ILMatcher cursor(flow_graph, entry);
+  // clang-format off
+  RELEASE_ASSERT(cursor.TryMatch({
+    kMatchAndMoveFunctionEntry,
+    kMatchAndMoveCheckStackOverflow,
+    kMoveDebugStepChecks,
+    kMatchAndMoveStaticCall,
+    kMatchAndMoveStaticCall,
+    {kMatchAndMoveInstanceCall, &call_add},
+    kMoveDebugStepChecks,
+    kMatchReturn,
+  }));
+  // clang-format on
+
+  EXPECT(call_add != nullptr);
+  EXPECT(call_add->function_name().Equals("add"));
+  EXPECT(call_add->entry_kind() == Code::EntryKind::kUnchecked);
+}
+
 }  // namespace dart
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index fa468cc..350e06d 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -5,6 +5,8 @@
 #include "vm/compiler/frontend/kernel_to_il.h"
 
 #include "platform/assert.h"
+#include "platform/globals.h"
+#include "vm/class_id.h"
 #include "vm/compiler/aot/precompiler.h"
 #include "vm/compiler/backend/il.h"
 #include "vm/compiler/backend/il_printer.h"
@@ -12,13 +14,17 @@
 #include "vm/compiler/backend/range_analysis.h"
 #include "vm/compiler/ffi/abi.h"
 #include "vm/compiler/ffi/marshaller.h"
+#include "vm/compiler/ffi/native_calling_convention.h"
+#include "vm/compiler/ffi/native_type.h"
 #include "vm/compiler/ffi/recognized_method.h"
 #include "vm/compiler/frontend/kernel_binary_flowgraph.h"
 #include "vm/compiler/frontend/kernel_translation_helper.h"
 #include "vm/compiler/frontend/prologue_builder.h"
 #include "vm/compiler/jit/compiler.h"
+#include "vm/compiler/runtime_api.h"
 #include "vm/kernel_isolate.h"
 #include "vm/kernel_loader.h"
+#include "vm/log.h"
 #include "vm/longjump.h"
 #include "vm/native_entry.h"
 #include "vm/object_store.h"
@@ -26,6 +32,7 @@
 #include "vm/resolver.h"
 #include "vm/scopes.h"
 #include "vm/stack_frame.h"
+#include "vm/symbols.h"
 
 namespace dart {
 namespace kernel {
@@ -3558,6 +3565,67 @@
   fragment.current->AsDefinition()->set_range(range);
 }
 
+static classid_t TypedDataCidUnboxed(Representation unboxed_representation) {
+  switch (unboxed_representation) {
+    case kUnboxedFloat:
+      // Note kTypedDataFloat32ArrayCid loads kUnboxedDouble.
+      UNREACHABLE();
+      return kTypedDataFloat32ArrayCid;
+    case kUnboxedInt32:
+      return kTypedDataInt32ArrayCid;
+    case kUnboxedUint32:
+      return kTypedDataUint32ArrayCid;
+    case kUnboxedInt64:
+      return kTypedDataInt64ArrayCid;
+    case kUnboxedDouble:
+      return kTypedDataFloat64ArrayCid;
+    default:
+      UNREACHABLE();
+  }
+  UNREACHABLE();
+}
+
+Fragment FlowGraphBuilder::StoreIndexedTypedDataUnboxed(
+    Representation unboxed_representation,
+    intptr_t index_scale,
+    bool index_unboxed) {
+  ASSERT(unboxed_representation == kUnboxedInt32 ||
+         unboxed_representation == kUnboxedUint32 ||
+         unboxed_representation == kUnboxedInt64 ||
+         unboxed_representation == kUnboxedFloat ||
+         unboxed_representation == kUnboxedDouble);
+  Fragment fragment;
+  if (unboxed_representation == kUnboxedFloat) {
+    fragment += BitCast(kUnboxedFloat, kUnboxedInt32);
+    unboxed_representation = kUnboxedInt32;
+  }
+  fragment += StoreIndexedTypedData(TypedDataCidUnboxed(unboxed_representation),
+                                    index_scale, index_unboxed);
+  return fragment;
+}
+
+Fragment FlowGraphBuilder::LoadIndexedTypedDataUnboxed(
+    Representation unboxed_representation,
+    intptr_t index_scale,
+    bool index_unboxed) {
+  ASSERT(unboxed_representation == kUnboxedInt32 ||
+         unboxed_representation == kUnboxedUint32 ||
+         unboxed_representation == kUnboxedInt64 ||
+         unboxed_representation == kUnboxedFloat ||
+         unboxed_representation == kUnboxedDouble);
+  Representation representation_for_load = unboxed_representation;
+  if (unboxed_representation == kUnboxedFloat) {
+    representation_for_load = kUnboxedInt32;
+  }
+  Fragment fragment;
+  fragment += LoadIndexed(TypedDataCidUnboxed(representation_for_load),
+                          index_scale, index_unboxed);
+  if (unboxed_representation == kUnboxedFloat) {
+    fragment += BitCast(kUnboxedInt32, kUnboxedFloat);
+  }
+  return fragment;
+}
+
 Fragment FlowGraphBuilder::EnterHandleScope() {
   auto* instr = new (Z)
       EnterHandleScopeInstr(EnterHandleScopeInstr::Kind::kEnterHandleScope);
@@ -3661,7 +3729,7 @@
     const compiler::ffi::CallbackMarshaller& marshaller) {
   auto* instr = new (Z) NativeReturnInstr(TokenPosition::kNoSource, Pop(),
                                           marshaller, DeoptId::kNone);
-  return Fragment(instr);
+  return Fragment(instr).closed();
 }
 
 Fragment FlowGraphBuilder::FfiPointerFromAddress(const Type& result_type) {
@@ -3703,10 +3771,297 @@
   return Fragment(instr);
 }
 
-Fragment FlowGraphBuilder::FfiConvertArgumentToDart(
+Fragment FlowGraphBuilder::WrapTypedDataBaseInStruct(
+    const AbstractType& struct_type) {
+  const auto& struct_sub_class = Class::ZoneHandle(Z, struct_type.type_class());
+  struct_sub_class.EnsureIsFinalized(thread_);
+  const auto& lib_ffi = Library::Handle(Z, Library::FfiLibrary());
+  const auto& struct_class =
+      Class::Handle(Z, lib_ffi.LookupClass(Symbols::Struct()));
+  const auto& struct_addressof = Field::ZoneHandle(
+      Z, struct_class.LookupInstanceFieldAllowPrivate(Symbols::_addressOf()));
+  ASSERT(!struct_addressof.IsNull());
+
+  Fragment body;
+  LocalVariable* typed_data = MakeTemporary("typed_data_base");
+  body += AllocateObject(TokenPosition::kNoSource, struct_sub_class, 0);
+  body += LoadLocal(MakeTemporary("struct"));  // Duplicate Struct.
+  body += LoadLocal(typed_data);
+  body += StoreInstanceField(struct_addressof,
+                             StoreInstanceFieldInstr::Kind::kInitializing);
+  body += DropTempsPreserveTop(1);  // Drop TypedData.
+  return body;
+}
+
+Fragment FlowGraphBuilder::LoadTypedDataBaseFromStruct() {
+  const Library& lib_ffi = Library::Handle(zone_, Library::FfiLibrary());
+  const Class& struct_class =
+      Class::Handle(zone_, lib_ffi.LookupClass(Symbols::Struct()));
+  const Field& struct_addressof = Field::ZoneHandle(
+      zone_,
+      struct_class.LookupInstanceFieldAllowPrivate(Symbols::_addressOf()));
+  ASSERT(!struct_addressof.IsNull());
+
+  Fragment body;
+  body += LoadField(struct_addressof, /*calls_initializer=*/false);
+  return body;
+}
+
+Fragment FlowGraphBuilder::CopyFromStructToStack(
+    LocalVariable* variable,
+    const GrowableArray<Representation>& representations) {
+  Fragment body;
+  const intptr_t num_defs = representations.length();
+  int offset_in_bytes = 0;
+  for (intptr_t i = 0; i < num_defs; i++) {
+    body += LoadLocal(variable);
+    body += LoadTypedDataBaseFromStruct();
+    body += LoadUntagged(compiler::target::Pointer::data_field_offset());
+    body += IntConstant(offset_in_bytes);
+    const Representation representation = representations[i];
+    offset_in_bytes += RepresentationUtils::ValueSize(representation);
+    body += LoadIndexedTypedDataUnboxed(representation, /*index_scale=*/1,
+                                        /*index_unboxed=*/false);
+  }
+  return body;
+}
+
+Fragment FlowGraphBuilder::PopFromStackToTypedDataBase(
+    ZoneGrowableArray<LocalVariable*>* definitions,
+    const GrowableArray<Representation>& representations) {
+  Fragment body;
+  const intptr_t num_defs = representations.length();
+  ASSERT(definitions->length() == num_defs);
+
+  LocalVariable* uint8_list = MakeTemporary("uint8_list");
+  int offset_in_bytes = 0;
+  for (intptr_t i = 0; i < num_defs; i++) {
+    const Representation representation = representations[i];
+    body += LoadLocal(uint8_list);
+    body += LoadUntagged(compiler::target::TypedDataBase::data_field_offset());
+    body += IntConstant(offset_in_bytes);
+    body += LoadLocal(definitions->At(i));
+    body += StoreIndexedTypedDataUnboxed(representation, /*index_scale=*/1,
+                                         /*index_unboxed=*/false);
+    offset_in_bytes += RepresentationUtils::ValueSize(representation);
+  }
+  body += DropTempsPreserveTop(num_defs);  // Drop chunck defs keep TypedData.
+  return body;
+}
+
+static intptr_t chunk_size(intptr_t bytes_left) {
+  ASSERT(bytes_left >= 1);
+  if (bytes_left >= 8 && compiler::target::kWordSize == 8) {
+    return 8;
+  }
+  if (bytes_left >= 4) {
+    return 4;
+  }
+  if (bytes_left >= 2) {
+    return 2;
+  }
+  return 1;
+}
+
+static classid_t typed_data_cid(intptr_t chunk_size) {
+  switch (chunk_size) {
+    case 8:
+      return kTypedDataInt64ArrayCid;
+    case 4:
+      return kTypedDataInt32ArrayCid;
+    case 2:
+      return kTypedDataInt16ArrayCid;
+    case 1:
+      return kTypedDataInt8ArrayCid;
+  }
+  UNREACHABLE();
+}
+
+Fragment FlowGraphBuilder::CopyFromTypedDataBaseToUnboxedAddress(
+    intptr_t length_in_bytes) {
+  Fragment body;
+  Value* unboxed_address_value = Pop();
+  LocalVariable* typed_data_base = MakeTemporary("typed_data_base");
+  Push(unboxed_address_value->definition());
+  LocalVariable* unboxed_address = MakeTemporary("unboxed_address");
+
+  intptr_t offset_in_bytes = 0;
+  while (offset_in_bytes < length_in_bytes) {
+    const intptr_t bytes_left = length_in_bytes - offset_in_bytes;
+    const intptr_t chunk_sizee = chunk_size(bytes_left);
+    const classid_t typed_data_cidd = typed_data_cid(chunk_sizee);
+
+    body += LoadLocal(typed_data_base);
+    body += LoadUntagged(compiler::target::TypedDataBase::data_field_offset());
+    body += IntConstant(offset_in_bytes);
+    body += LoadIndexed(typed_data_cidd, /*index_scale=*/1,
+                        /*index_unboxed=*/false);
+    LocalVariable* chunk_value = MakeTemporary("chunk_value");
+
+    body += LoadLocal(unboxed_address);
+    body += ConvertUnboxedToUntagged(kUnboxedFfiIntPtr);
+    body += IntConstant(offset_in_bytes);
+    body += LoadLocal(chunk_value);
+    body += StoreIndexedTypedData(typed_data_cidd, /*index_scale=*/1,
+                                  /*index_unboxed=*/false);
+    body += DropTemporary(&chunk_value);
+
+    offset_in_bytes += chunk_sizee;
+  }
+  ASSERT(offset_in_bytes == length_in_bytes);
+
+  body += DropTemporary(&unboxed_address);
+  body += DropTemporary(&typed_data_base);
+  return body;
+}
+
+Fragment FlowGraphBuilder::CopyFromUnboxedAddressToTypedDataBase(
+    intptr_t length_in_bytes) {
+  Fragment body;
+  Value* typed_data_base_value = Pop();
+  LocalVariable* unboxed_address = MakeTemporary("unboxed_address");
+  Push(typed_data_base_value->definition());
+  LocalVariable* typed_data_base = MakeTemporary("typed_data_base");
+
+  intptr_t offset_in_bytes = 0;
+  while (offset_in_bytes < length_in_bytes) {
+    const intptr_t bytes_left = length_in_bytes - offset_in_bytes;
+    const intptr_t chunk_sizee = chunk_size(bytes_left);
+    const classid_t typed_data_cidd = typed_data_cid(chunk_sizee);
+
+    body += LoadLocal(unboxed_address);
+    body += ConvertUnboxedToUntagged(kUnboxedFfiIntPtr);
+    body += IntConstant(offset_in_bytes);
+    body += LoadIndexed(typed_data_cidd, /*index_scale=*/1,
+                        /*index_unboxed=*/false);
+    LocalVariable* chunk_value = MakeTemporary("chunk_value");
+
+    body += LoadLocal(typed_data_base);
+    body += LoadUntagged(compiler::target::TypedDataBase::data_field_offset());
+    body += IntConstant(offset_in_bytes);
+    body += LoadLocal(chunk_value);
+    body += StoreIndexedTypedData(typed_data_cidd, /*index_scale=*/1,
+                                  /*index_unboxed=*/false);
+    body += DropTemporary(&chunk_value);
+
+    offset_in_bytes += chunk_sizee;
+  }
+  ASSERT(offset_in_bytes == length_in_bytes);
+
+  body += DropTemporary(&typed_data_base);
+  body += DropTemporary(&unboxed_address);
+  return body;
+}
+
+Fragment FlowGraphBuilder::FfiCallConvertStructArgumentToNative(
+    LocalVariable* variable,
     const compiler::ffi::BaseMarshaller& marshaller,
     intptr_t arg_index) {
   Fragment body;
+  const auto& native_loc = marshaller.Location(arg_index);
+  if (native_loc.IsStack() || native_loc.IsMultiple()) {
+    // Break struct in pieces to separate IL definitions to pass those
+    // separate definitions into the FFI call.
+    GrowableArray<Representation> representations;
+    marshaller.RepsInFfiCall(arg_index, &representations);
+    body += CopyFromStructToStack(variable, representations);
+  } else {
+    ASSERT(native_loc.IsPointerToMemory());
+    // Only load the typed data, do copying in the FFI call machine code.
+    body += LoadLocal(variable);  // User-defined struct.
+    body += LoadTypedDataBaseFromStruct();
+  }
+  return body;
+}
+
+Fragment FlowGraphBuilder::FfiCallConvertStructReturnToDart(
+    const compiler::ffi::BaseMarshaller& marshaller,
+    intptr_t arg_index) {
+  Fragment body;
+  // The typed data is allocated before the FFI call, and is populated in
+  // machine code. So, here, it only has to be wrapped in the struct class.
+  const auto& struct_type =
+      AbstractType::Handle(Z, marshaller.CType(arg_index));
+  body += WrapTypedDataBaseInStruct(struct_type);
+  return body;
+}
+
+Fragment FlowGraphBuilder::FfiCallbackConvertStructArgumentToDart(
+    const compiler::ffi::BaseMarshaller& marshaller,
+    intptr_t arg_index,
+    ZoneGrowableArray<LocalVariable*>* definitions) {
+  const intptr_t length_in_bytes =
+      marshaller.Location(arg_index).payload_type().SizeInBytes();
+
+  Fragment body;
+  if ((marshaller.Location(arg_index).IsMultiple() ||
+       marshaller.Location(arg_index).IsStack())) {
+    // Allocate and populate a TypedData from the individual NativeParameters.
+    body += IntConstant(length_in_bytes);
+    body +=
+        AllocateTypedData(TokenPosition::kNoSource, kTypedDataUint8ArrayCid);
+    GrowableArray<Representation> representations;
+    marshaller.RepsInFfiCall(arg_index, &representations);
+    body += PopFromStackToTypedDataBase(definitions, representations);
+  } else {
+    ASSERT(marshaller.Location(arg_index).IsPointerToMemory());
+    // Allocate a TypedData and copy contents pointed to by an address into it.
+    LocalVariable* address_of_struct = MakeTemporary("address_of_struct");
+    body += IntConstant(length_in_bytes);
+    body +=
+        AllocateTypedData(TokenPosition::kNoSource, kTypedDataUint8ArrayCid);
+    LocalVariable* typed_data_base = MakeTemporary("typed_data_base");
+    body += LoadLocal(address_of_struct);
+    body += LoadLocal(typed_data_base);
+    body += CopyFromUnboxedAddressToTypedDataBase(length_in_bytes);
+    body += DropTempsPreserveTop(1);  // address_of_struct.
+  }
+  // Wrap typed data in struct class.
+  const auto& struct_type =
+      AbstractType::Handle(Z, marshaller.CType(arg_index));
+  body += WrapTypedDataBaseInStruct(struct_type);
+  return body;
+}
+
+Fragment FlowGraphBuilder::FfiCallbackConvertStructReturnToNative(
+    const compiler::ffi::CallbackMarshaller& marshaller,
+    intptr_t arg_index) {
+  Fragment body;
+  const auto& native_loc = marshaller.Location(arg_index);
+  if (native_loc.IsMultiple()) {
+    // We pass in typed data to native return instruction, and do the copying
+    // in machine code.
+    body += LoadTypedDataBaseFromStruct();
+  } else {
+    ASSERT(native_loc.IsPointerToMemory());
+    // We copy the data into the right location in IL.
+    const intptr_t length_in_bytes =
+        marshaller.Location(arg_index).payload_type().SizeInBytes();
+
+    body += LoadTypedDataBaseFromStruct();
+    LocalVariable* typed_data_base = MakeTemporary("typed_data_base");
+
+    auto* pointer_to_return =
+        new (Z) NativeParameterInstr(marshaller, compiler::ffi::kResultIndex);
+    Push(pointer_to_return);  // Address where return value should be stored.
+    body <<= pointer_to_return;
+    body += UnboxTruncate(kUnboxedFfiIntPtr);
+    LocalVariable* unboxed_address = MakeTemporary("unboxed_address");
+
+    body += LoadLocal(typed_data_base);
+    body += LoadLocal(unboxed_address);
+    body += CopyFromTypedDataBaseToUnboxedAddress(length_in_bytes);
+    body += DropTempsPreserveTop(1);  // Keep address, drop typed_data_base.
+  }
+  return body;
+}
+
+Fragment FlowGraphBuilder::FfiConvertPrimitiveToDart(
+    const compiler::ffi::BaseMarshaller& marshaller,
+    intptr_t arg_index) {
+  ASSERT(!marshaller.IsStruct(arg_index));
+
+  Fragment body;
   if (marshaller.IsPointer(arg_index)) {
     body += Box(kUnboxedFfiIntPtr);
     body += FfiPointerFromAddress(
@@ -3718,8 +4073,9 @@
     body += NullConstant();
   } else {
     if (marshaller.RequiresBitCast(arg_index)) {
-      body += BitCast(marshaller.RepInFfiCall(arg_index),
-                      marshaller.RepInDart(arg_index));
+      body += BitCast(
+          marshaller.RepInFfiCall(marshaller.FirstDefinitionIndex(arg_index)),
+          marshaller.RepInDart(arg_index));
     }
 
     body += Box(marshaller.RepInDart(arg_index));
@@ -3727,12 +4083,13 @@
   return body;
 }
 
-Fragment FlowGraphBuilder::FfiConvertArgumentToNative(
+Fragment FlowGraphBuilder::FfiConvertPrimitiveToNative(
     const compiler::ffi::BaseMarshaller& marshaller,
     intptr_t arg_index,
     LocalVariable* api_local_scope) {
-  Fragment body;
+  ASSERT(!marshaller.IsStruct(arg_index));
 
+  Fragment body;
   if (marshaller.IsPointer(arg_index)) {
     // This can only be Pointer, so it is always safe to LoadUntagged.
     body += LoadUntagged(compiler::target::Pointer::data_field_offset());
@@ -3744,8 +4101,9 @@
   }
 
   if (marshaller.RequiresBitCast(arg_index)) {
-    body += BitCast(marshaller.RepInDart(arg_index),
-                    marshaller.RepInFfiCall(arg_index));
+    body += BitCast(
+        marshaller.RepInDart(arg_index),
+        marshaller.RepInFfiCall(marshaller.FirstDefinitionIndex(arg_index)));
   }
 
   return body;
@@ -3817,14 +4175,30 @@
     ++try_depth_;
 
     body += EnterHandleScope();
-    api_local_scope = MakeTemporary();
+    api_local_scope = MakeTemporary("api_local_scope");
+  }
+
+  // Allocate typed data before FfiCall and pass it in to ffi call if needed.
+  LocalVariable* typed_data = nullptr;
+  if (marshaller.PassTypedData()) {
+    body += IntConstant(marshaller.TypedDataSizeInBytes());
+    body +=
+        AllocateTypedData(TokenPosition::kNoSource, kTypedDataUint8ArrayCid);
+    typed_data = MakeTemporary();
   }
 
   // Unbox and push the arguments.
   for (intptr_t i = 0; i < marshaller.num_args(); i++) {
-    body += LoadLocal(
-        parsed_function_->ParameterVariable(kFirstArgumentParameterOffset + i));
-    body += FfiConvertArgumentToNative(marshaller, i, api_local_scope);
+    if (marshaller.IsStruct(i)) {
+      body += FfiCallConvertStructArgumentToNative(
+          parsed_function_->ParameterVariable(kFirstArgumentParameterOffset +
+                                              i),
+          marshaller, i);
+    } else {
+      body += LoadLocal(parsed_function_->ParameterVariable(
+          kFirstArgumentParameterOffset + i));
+      body += FfiConvertPrimitiveToNative(marshaller, i, api_local_scope);
+    }
   }
 
   // Push the function pointer, which is stored (as Pointer object) in the
@@ -3840,6 +4214,11 @@
   // This can only be Pointer, so it is always safe to LoadUntagged.
   body += LoadUntagged(compiler::target::Pointer::data_field_offset());
   body += ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr);
+
+  if (marshaller.PassTypedData()) {
+    body += LoadLocal(typed_data);
+  }
+
   body += FfiCall(marshaller);
 
   for (intptr_t i = 0; i < marshaller.num_args(); i++) {
@@ -3850,7 +4229,23 @@
     }
   }
 
-  body += FfiConvertArgumentToDart(marshaller, compiler::ffi::kResultIndex);
+  const intptr_t num_defs = marshaller.NumReturnDefinitions();
+  ASSERT(num_defs >= 1);
+  auto defs = new (Z) ZoneGrowableArray<LocalVariable*>(Z, num_defs);
+  LocalVariable* def = MakeTemporary();
+  defs->Add(def);
+
+  if (marshaller.PassTypedData()) {
+    // Drop call result, typed data with contents is already on the stack.
+    body += Drop();
+  }
+
+  if (marshaller.IsStruct(compiler::ffi::kResultIndex)) {
+    body += FfiCallConvertStructReturnToDart(marshaller,
+                                             compiler::ffi::kResultIndex);
+  } else {
+    body += FfiConvertPrimitiveToDart(marshaller, compiler::ffi::kResultIndex);
+  }
 
   if (signature_contains_handles) {
     body += DropTempsPreserveTop(1);  // Drop api_local_scope.
@@ -3909,10 +4304,23 @@
 
   // Box and push the arguments.
   for (intptr_t i = 0; i < marshaller.num_args(); i++) {
-    auto* parameter = new (Z) NativeParameterInstr(marshaller, i);
-    Push(parameter);
-    body <<= parameter;
-    body += FfiConvertArgumentToDart(marshaller, i);
+    const intptr_t num_defs = marshaller.NumDefinitions(i);
+    auto defs = new (Z) ZoneGrowableArray<LocalVariable*>(Z, num_defs);
+
+    for (intptr_t j = 0; j < num_defs; j++) {
+      const intptr_t def_index = marshaller.DefinitionIndex(j, i);
+      auto* parameter = new (Z) NativeParameterInstr(marshaller, def_index);
+      Push(parameter);
+      body <<= parameter;
+      LocalVariable* def = MakeTemporary();
+      defs->Add(def);
+    }
+
+    if (marshaller.IsStruct(i)) {
+      body += FfiCallbackConvertStructArgumentToDart(marshaller, i, defs);
+    } else {
+      body += FfiConvertPrimitiveToDart(marshaller, i);
+    }
   }
 
   // Call the target.
@@ -3923,7 +4331,6 @@
                      Function::ZoneHandle(Z, function.FfiCallbackTarget()),
                      marshaller.num_args(), Array::empty_array(),
                      ICData::kNoRebind);
-
   if (marshaller.IsVoid(compiler::ffi::kResultIndex)) {
     body += Drop();
     body += IntConstant(0);
@@ -3932,8 +4339,15 @@
         CheckNullOptimized(TokenPosition::kNoSource,
                            String::ZoneHandle(Z, marshaller.function_name()));
   }
-  body += FfiConvertArgumentToNative(marshaller, compiler::ffi::kResultIndex,
-                                     /*api_local_scope=*/nullptr);
+
+  if (marshaller.IsStruct(compiler::ffi::kResultIndex)) {
+    body += FfiCallbackConvertStructReturnToNative(marshaller,
+                                                   compiler::ffi::kResultIndex);
+  } else {
+    body += FfiConvertPrimitiveToNative(marshaller, compiler::ffi::kResultIndex,
+                                        /*api_local_scope=*/nullptr);
+  }
+
   body += NativeReturn(marshaller);
 
   --try_depth_;
@@ -3955,13 +4369,32 @@
     catch_body += UnboxTruncate(kUnboxedFfiIntPtr);
   } else if (marshaller.IsHandle(compiler::ffi::kResultIndex)) {
     catch_body += UnhandledException();
-    catch_body += FfiConvertArgumentToNative(
-        marshaller, compiler::ffi::kResultIndex, /*api_local_scope=*/nullptr);
+    catch_body +=
+        FfiConvertPrimitiveToNative(marshaller, compiler::ffi::kResultIndex,
+                                    /*api_local_scope=*/nullptr);
+
+  } else if (marshaller.IsStruct(compiler::ffi::kResultIndex)) {
+    ASSERT(function.FfiCallbackExceptionalReturn() == Object::null());
+    // Manufacture empty result.
+    const intptr_t size =
+        Utils::RoundUp(marshaller.Location(compiler::ffi::kResultIndex)
+                           .payload_type()
+                           .SizeInBytes(),
+                       compiler::target::kWordSize);
+    catch_body += IntConstant(size);
+    catch_body +=
+        AllocateTypedData(TokenPosition::kNoSource, kTypedDataUint8ArrayCid);
+    catch_body += WrapTypedDataBaseInStruct(
+        AbstractType::Handle(Z, marshaller.CType(compiler::ffi::kResultIndex)));
+    catch_body += FfiCallbackConvertStructReturnToNative(
+        marshaller, compiler::ffi::kResultIndex);
+
   } else {
     catch_body += Constant(
         Instance::ZoneHandle(Z, function.FfiCallbackExceptionalReturn()));
-    catch_body += FfiConvertArgumentToNative(
-        marshaller, compiler::ffi::kResultIndex, /*api_local_scope=*/nullptr);
+    catch_body +=
+        FfiConvertPrimitiveToNative(marshaller, compiler::ffi::kResultIndex,
+                                    /*api_local_scope=*/nullptr);
   }
 
   catch_body += NativeReturn(marshaller);
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index 1041f9c..5b6b303 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -252,6 +252,17 @@
   bool NeedsDebugStepCheck(const Function& function, TokenPosition position);
   bool NeedsDebugStepCheck(Value* value, TokenPosition position);
 
+  // Deals with StoreIndexed not working with kUnboxedFloat.
+  // TODO(dartbug.com/43448): Remove this workaround.
+  Fragment StoreIndexedTypedDataUnboxed(Representation unboxed_representation,
+                                        intptr_t index_scale,
+                                        bool index_unboxed);
+  // Deals with LoadIndexed not working with kUnboxedFloat.
+  // TODO(dartbug.com/43448): Remove this workaround.
+  Fragment LoadIndexedTypedDataUnboxed(Representation unboxed_representation,
+                                       intptr_t index_scale,
+                                       bool index_unboxed);
+
   // Truncates (instead of deoptimizing) if the origin does not fit into the
   // target representation.
   Fragment UnboxTruncate(Representation to);
@@ -266,16 +277,81 @@
 
   // Pops a Dart object and push the unboxed native version, according to the
   // semantics of FFI argument translation.
-  Fragment FfiConvertArgumentToNative(
+  //
+  // Works for FFI call arguments, and FFI callback return values.
+  Fragment FfiConvertPrimitiveToNative(
       const compiler::ffi::BaseMarshaller& marshaller,
       intptr_t arg_index,
       LocalVariable* api_local_scope);
 
-  // Reverse of 'FfiConvertArgumentToNative'.
-  Fragment FfiConvertArgumentToDart(
+  // Pops an unboxed native value, and pushes a Dart object, according to the
+  // semantics of FFI argument translation.
+  //
+  // Works for FFI call return values, and FFI callback arguments.
+  Fragment FfiConvertPrimitiveToDart(
       const compiler::ffi::BaseMarshaller& marshaller,
       intptr_t arg_index);
 
+  // We pass in `variable` instead of on top of the stack so that we can have
+  // multiple consecutive calls that keep only struct parts on the stack with
+  // no struct parts in between.
+  Fragment FfiCallConvertStructArgumentToNative(
+      LocalVariable* variable,
+      const compiler::ffi::BaseMarshaller& marshaller,
+      intptr_t arg_index);
+
+  Fragment FfiCallConvertStructReturnToDart(
+      const compiler::ffi::BaseMarshaller& marshaller,
+      intptr_t arg_index);
+
+  // We pass in multiple `definitions`, which are also expected to be the top
+  // of the stack. This eases storing each definition in the resulting struct.
+  Fragment FfiCallbackConvertStructArgumentToDart(
+      const compiler::ffi::BaseMarshaller& marshaller,
+      intptr_t arg_index,
+      ZoneGrowableArray<LocalVariable*>* definitions);
+
+  Fragment FfiCallbackConvertStructReturnToNative(
+      const compiler::ffi::CallbackMarshaller& marshaller,
+      intptr_t arg_index);
+
+  // Wraps a TypedDataBase from the stack and wraps it in a subclass of Struct.
+  Fragment WrapTypedDataBaseInStruct(const AbstractType& struct_type);
+
+  // Loads the addressOf field from a subclass of Struct.
+  Fragment LoadTypedDataBaseFromStruct();
+
+  // Breaks up a subclass of Struct in multiple definitions and puts them on
+  // the stack.
+  //
+  // Takes in the Struct as a local `variable` so that can be anywhere on the
+  // stack and this function can be called multiple times to leave only the
+  // results of this function on the stack without any Structs in between.
+  //
+  // The struct contents are heterogeneous, so pass in `representations` to
+  // know what representation to load.
+  Fragment CopyFromStructToStack(
+      LocalVariable* variable,
+      const GrowableArray<Representation>& representations);
+
+  // Copy `definitions` into TypedData.
+  //
+  // Expects the TypedData on top of the stack and `definitions` right under it.
+  //
+  // Leaves TypedData on stack.
+  //
+  // The struct contents are heterogeneous, so pass in `representations` to
+  // know what representation to load.
+  Fragment PopFromStackToTypedDataBase(
+      ZoneGrowableArray<LocalVariable*>* definitions,
+      const GrowableArray<Representation>& representations);
+
+  // Copies bytes from a TypedDataBase to the address of an kUnboxedFfiIntPtr.
+  Fragment CopyFromTypedDataBaseToUnboxedAddress(intptr_t length_in_bytes);
+
+  // Copies bytes from the address of an kUnboxedFfiIntPtr to a TypedDataBase.
+  Fragment CopyFromUnboxedAddressToTypedDataBase(intptr_t length_in_bytes);
+
   // Generates a call to `Thread::EnterApiScope`.
   Fragment EnterHandleScope();
 
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index 3e142f4..d88ab4d 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -212,6 +212,15 @@
   ASSERT(thread->IsMutatorThread());
   const Function& function = Function::CheckedHandle(zone, arguments.ArgAt(0));
 
+  if (FLAG_enable_isolate_groups) {
+    // Another isolate's mutator thread may have created [function] and
+    // published it via an ICData, MegamorphicCache etc. Entering the lock below
+    // is an acquire operation that pairs with the release operation when the
+    // other isolate exited the lock, ensuring the initializing stores for
+    // [function] are visible in the current thread.
+    SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
+  }
+
   // In single-isolate scenarios the lazy compile stub is only invoked if
   // there's no existing code. In multi-isolate scenarios with shared JITed code
   // we can end up in the lazy compile runtime entry here with code being
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index cb104ad..0aa1329 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -1044,6 +1044,7 @@
   static word unboxed_int64_runtime_arg_offset();
 
   static word callback_code_offset();
+  static word callback_stack_return_offset();
 
   static word AllocateArray_entry_point_offset();
   static word write_barrier_code_offset();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 63c13d4..e48bedc 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -248,7 +248,7 @@
     Thread_allocate_object_slow_entry_point_offset = 288;
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 196;
-static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 728;
+static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 732;
 static constexpr dart::compiler::target::word
     Thread_auto_scope_native_wrapper_entry_point_offset = 332;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 112;
@@ -259,7 +259,7 @@
     Thread_call_to_runtime_entry_point_offset = 268;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 136;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 736;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 740;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -301,7 +301,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 132;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    724;
+    728;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
@@ -382,6 +382,8 @@
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     36;
 static constexpr dart::compiler::target::word Thread_callback_code_offset = 720;
+static constexpr dart::compiler::target::word
+    Thread_callback_stack_return_offset = 724;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -768,7 +770,7 @@
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 376;
 static constexpr dart::compiler::target::word Thread_api_top_scope_offset =
-    1464;
+    1472;
 static constexpr dart::compiler::target::word
     Thread_auto_scope_native_wrapper_entry_point_offset = 648;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 208;
@@ -779,7 +781,7 @@
     Thread_call_to_runtime_entry_point_offset = 520;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 256;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1480;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1488;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -821,7 +823,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 248;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    1456;
+    1464;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
@@ -903,6 +905,8 @@
     72;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
     1448;
+static constexpr dart::compiler::target::word
+    Thread_callback_stack_return_offset = 1456;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -1288,7 +1292,7 @@
     Thread_allocate_object_slow_entry_point_offset = 288;
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 196;
-static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 696;
+static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 700;
 static constexpr dart::compiler::target::word
     Thread_auto_scope_native_wrapper_entry_point_offset = 332;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 112;
@@ -1299,7 +1303,7 @@
     Thread_call_to_runtime_entry_point_offset = 268;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 136;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 704;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 708;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -1341,7 +1345,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 132;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    692;
+    696;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
@@ -1422,6 +1426,8 @@
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     36;
 static constexpr dart::compiler::target::word Thread_callback_code_offset = 688;
+static constexpr dart::compiler::target::word
+    Thread_callback_stack_return_offset = 692;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -1805,7 +1811,7 @@
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 376;
 static constexpr dart::compiler::target::word Thread_api_top_scope_offset =
-    1536;
+    1544;
 static constexpr dart::compiler::target::word
     Thread_auto_scope_native_wrapper_entry_point_offset = 648;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 208;
@@ -1816,7 +1822,7 @@
     Thread_call_to_runtime_entry_point_offset = 520;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 256;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1552;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1560;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -1858,7 +1864,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 248;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    1528;
+    1536;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
@@ -1940,6 +1946,8 @@
     72;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
     1520;
+static constexpr dart::compiler::target::word
+    Thread_callback_stack_return_offset = 1528;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -2325,7 +2333,7 @@
     Thread_allocate_object_slow_entry_point_offset = 288;
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 196;
-static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 728;
+static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 732;
 static constexpr dart::compiler::target::word
     Thread_auto_scope_native_wrapper_entry_point_offset = 332;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 112;
@@ -2336,7 +2344,7 @@
     Thread_call_to_runtime_entry_point_offset = 268;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 136;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 736;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 740;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -2378,7 +2386,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 132;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    724;
+    728;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
@@ -2459,6 +2467,8 @@
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     36;
 static constexpr dart::compiler::target::word Thread_callback_code_offset = 720;
+static constexpr dart::compiler::target::word
+    Thread_callback_stack_return_offset = 724;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -2839,7 +2849,7 @@
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 376;
 static constexpr dart::compiler::target::word Thread_api_top_scope_offset =
-    1464;
+    1472;
 static constexpr dart::compiler::target::word
     Thread_auto_scope_native_wrapper_entry_point_offset = 648;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 208;
@@ -2850,7 +2860,7 @@
     Thread_call_to_runtime_entry_point_offset = 520;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 256;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1480;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1488;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -2892,7 +2902,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 248;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    1456;
+    1464;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
@@ -2974,6 +2984,8 @@
     72;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
     1448;
+static constexpr dart::compiler::target::word
+    Thread_callback_stack_return_offset = 1456;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -3353,7 +3365,7 @@
     Thread_allocate_object_slow_entry_point_offset = 288;
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 196;
-static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 696;
+static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 700;
 static constexpr dart::compiler::target::word
     Thread_auto_scope_native_wrapper_entry_point_offset = 332;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 112;
@@ -3364,7 +3376,7 @@
     Thread_call_to_runtime_entry_point_offset = 268;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 136;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 704;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 708;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -3406,7 +3418,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 132;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    692;
+    696;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
@@ -3487,6 +3499,8 @@
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     36;
 static constexpr dart::compiler::target::word Thread_callback_code_offset = 688;
+static constexpr dart::compiler::target::word
+    Thread_callback_stack_return_offset = 692;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -3864,7 +3878,7 @@
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 376;
 static constexpr dart::compiler::target::word Thread_api_top_scope_offset =
-    1536;
+    1544;
 static constexpr dart::compiler::target::word
     Thread_auto_scope_native_wrapper_entry_point_offset = 648;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 208;
@@ -3875,7 +3889,7 @@
     Thread_call_to_runtime_entry_point_offset = 520;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 256;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1552;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1560;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -3917,7 +3931,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 248;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    1528;
+    1536;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
@@ -3999,6 +4013,8 @@
     72;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
     1520;
+static constexpr dart::compiler::target::word
+    Thread_callback_stack_return_offset = 1528;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -4405,7 +4421,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 196;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    728;
+    732;
 static constexpr dart::compiler::target::word
     AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 332;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
@@ -4418,7 +4434,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 136;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    736;
+    740;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -4461,7 +4477,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 132;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 724;
+    AOT_Thread_exit_through_ffi_offset = 728;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 64;
@@ -4548,6 +4564,8 @@
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
     720;
 static constexpr dart::compiler::target::word
+    AOT_Thread_callback_stack_return_offset = 724;
+static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
     12;
@@ -4979,7 +4997,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 376;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    1464;
+    1472;
 static constexpr dart::compiler::target::word
     AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 648;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
@@ -4992,7 +5010,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 256;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1480;
+    1488;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -5035,7 +5053,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 248;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 1456;
+    AOT_Thread_exit_through_ffi_offset = 1464;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
@@ -5123,6 +5141,8 @@
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
     1448;
 static constexpr dart::compiler::target::word
+    AOT_Thread_callback_stack_return_offset = 1456;
+static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 16;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
     16;
@@ -5559,7 +5579,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 376;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    1536;
+    1544;
 static constexpr dart::compiler::target::word
     AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 648;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
@@ -5572,7 +5592,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 256;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1552;
+    1560;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -5615,7 +5635,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 248;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 1528;
+    AOT_Thread_exit_through_ffi_offset = 1536;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
@@ -5703,6 +5723,8 @@
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
     1520;
 static constexpr dart::compiler::target::word
+    AOT_Thread_callback_stack_return_offset = 1528;
+static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 16;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
     16;
@@ -6134,7 +6156,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 196;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    728;
+    732;
 static constexpr dart::compiler::target::word
     AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 332;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
@@ -6147,7 +6169,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 136;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    736;
+    740;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -6190,7 +6212,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 132;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 724;
+    AOT_Thread_exit_through_ffi_offset = 728;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 64;
@@ -6277,6 +6299,8 @@
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
     720;
 static constexpr dart::compiler::target::word
+    AOT_Thread_callback_stack_return_offset = 724;
+static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
     12;
@@ -6701,7 +6725,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 376;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    1464;
+    1472;
 static constexpr dart::compiler::target::word
     AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 648;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
@@ -6714,7 +6738,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 256;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1480;
+    1488;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -6757,7 +6781,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 248;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 1456;
+    AOT_Thread_exit_through_ffi_offset = 1464;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
@@ -6845,6 +6869,8 @@
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
     1448;
 static constexpr dart::compiler::target::word
+    AOT_Thread_callback_stack_return_offset = 1456;
+static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 16;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
     16;
@@ -7274,7 +7300,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 376;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    1536;
+    1544;
 static constexpr dart::compiler::target::word
     AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 648;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
@@ -7287,7 +7313,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 256;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1552;
+    1560;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -7330,7 +7356,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 248;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 1528;
+    AOT_Thread_exit_through_ffi_offset = 1536;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
@@ -7418,6 +7444,8 @@
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
     1520;
 static constexpr dart::compiler::target::word
+    AOT_Thread_callback_stack_return_offset = 1528;
+static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 16;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
     16;
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index bc52da9..347cf96 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -256,6 +256,7 @@
   FIELD(Thread, write_barrier_entry_point_offset)                              \
   FIELD(Thread, write_barrier_mask_offset)                                     \
   FIELD(Thread, callback_code_offset)                                          \
+  FIELD(Thread, callback_stack_return_offset)                                  \
   FIELD(TimelineStream, enabled_offset)                                        \
   FIELD(TwoByteString, data_offset)                                            \
   FIELD(Type, arguments_offset)                                                \
diff --git a/runtime/vm/compiler/stub_code_compiler.h b/runtime/vm/compiler/stub_code_compiler.h
index 5f3e09c..357c005 100644
--- a/runtime/vm/compiler/stub_code_compiler.h
+++ b/runtime/vm/compiler/stub_code_compiler.h
@@ -112,8 +112,8 @@
   static constexpr intptr_t kNativeCallbackTrampolineStackDelta = 2;
 #elif defined(TARGET_ARCH_IA32)
   static constexpr intptr_t kNativeCallbackTrampolineSize = 10;
-  static constexpr intptr_t kNativeCallbackSharedStubSize = 90;
-  static constexpr intptr_t kNativeCallbackTrampolineStackDelta = 2;
+  static constexpr intptr_t kNativeCallbackSharedStubSize = 134;
+  static constexpr intptr_t kNativeCallbackTrampolineStackDelta = 4;
 #elif defined(TARGET_ARCH_ARM)
   static constexpr intptr_t kNativeCallbackTrampolineSize = 12;
   static constexpr intptr_t kNativeCallbackSharedStubSize = 140;
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index 22a550e..e8d950d 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -375,6 +375,8 @@
 
   RegisterSet all_registers;
   all_registers.AddAllArgumentRegisters();
+  all_registers.Add(Location::RegisterLocation(
+      CallingConventions::kPointerToReturnStructRegisterCall));
 
   // The call below might clobber R9 (volatile, holding callback_id).
   all_registers.Add(Location::RegisterLocation(R9));
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index 4d499af..65939b2 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -213,7 +213,7 @@
 void StubCodeCompiler::GenerateJITCallbackTrampolines(
     Assembler* assembler,
     intptr_t next_callback_id) {
-  Label done;
+  Label done, ret_4;
 
   // EAX is volatile and doesn't hold any arguments.
   COMPILE_ASSERT(!IsArgumentRegister(EAX) && !IsCalleeSavedRegister(EAX));
@@ -232,16 +232,20 @@
 
   const intptr_t shared_stub_start = __ CodeSize();
 
-  // Save THR which is callee-saved.
+  // Save THR and EBX which are callee-saved.
   __ pushl(THR);
+  __ pushl(EBX);
+
+  // We need the callback ID after the call for return stack.
+  __ pushl(EAX);
 
   // THR & return address
-  COMPILE_ASSERT(StubCodeCompiler::kNativeCallbackTrampolineStackDelta == 2);
+  COMPILE_ASSERT(StubCodeCompiler::kNativeCallbackTrampolineStackDelta == 4);
 
   // Load the thread, verify the callback ID and exit the safepoint.
   //
   // We exit the safepoint inside DLRT_GetThreadForNativeCallbackTrampoline
-  // in order to safe code size on this shared stub.
+  // in order to save code size on this shared stub.
   {
     __ EnterFrame(0);
     __ ReserveAlignedFrameSpace(compiler::target::kWordSize);
@@ -278,14 +282,54 @@
   // the saved THR and the return address. The target will know to skip them.
   __ call(ECX);
 
+  // Register state:
+  // - callee saved registers (should be restored)
+  //   - EBX available as scratch because we restore it later.
+  //   - ESI(THR) contains thread
+  //   - EDI
+  // - return registers (should not be touched)
+  //   - EAX
+  //   - EDX
+  // - available scratch registers
+  //   - ECX free
+
+  // Load the return stack delta from the thread.
+  __ movl(ECX,
+          compiler::Address(
+              THR, compiler::target::Thread::callback_stack_return_offset()));
+  __ popl(EBX);  // Compiler callback id.
+  __ movzxb(EBX, __ ElementAddressForRegIndex(
+                     /*external=*/false,
+                     /*array_cid=*/kTypedDataUint8ArrayCid,
+                     /*index=*/1,
+                     /*index_unboxed=*/false,
+                     /*array=*/ECX,
+                     /*index=*/EBX));
+#if defined(DEBUG)
+  // Stack delta should be either 0 or 4.
+  Label check_done;
+  __ BranchIfZero(EBX, &check_done);
+  __ CompareImmediate(EBX, compiler::target::kWordSize);
+  __ BranchIf(EQUAL, &check_done);
+  __ Breakpoint();
+  __ Bind(&check_done);
+#endif
+
   // EnterSafepoint takes care to not clobber *any* registers (besides scratch).
   __ EnterSafepoint(/*scratch=*/ECX);
 
-  // Restore THR (callee-saved).
+  // Restore callee-saved registers.
+  __ movl(ECX, EBX);
+  __ popl(EBX);
   __ popl(THR);
 
+  __ cmpl(ECX, compiler::Immediate(Smi::RawValue(0)));
+  __ j(NOT_EQUAL, &ret_4, compiler::Assembler::kNearJump);
   __ ret();
 
+  __ Bind(&ret_4);
+  __ ret(Immediate(4));
+
   // 'kNativeCallbackSharedStubSize' is an upper bound because the exact
   // instruction size can vary slightly based on OS calling conventions.
   ASSERT((__ CodeSize() - shared_stub_start) <= kNativeCallbackSharedStubSize);
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index bc3c7cb..d5242f1 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -266,6 +266,15 @@
   static constexpr Register kSecondReturnReg = EDX;
   static constexpr Register kPointerToReturnStructRegisterReturn = kReturnReg;
 
+  // Whether the callee uses `ret 4` instead of `ret` to return with struct
+  // return values.
+  // See: https://c9x.me/x86/html/file_module_x86_id_280.html
+#if defined(_WIN32)
+  static const bool kUsesRet4 = false;
+#else
+  static const bool kUsesRet4 = true;
+#endif
+
   // Floating point values are returned on the "FPU stack" (in "ST" registers).
   // However, we use XMM0 in our compiler pipeline as the location.
   // The move from and to ST is done in FfiCallInstr::EmitNativeCode and
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index ea681ce..8ebeb8e 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -461,7 +461,7 @@
 
   COMPILE_ASSERT((kArgumentRegisters & kReservedCpuRegisters) == 0);
 
-  static constexpr Register kFfiAnyNonAbiRegister = RBX;
+  static constexpr Register kFfiAnyNonAbiRegister = R12;
   static constexpr Register kFirstNonArgumentRegister = RAX;
   static constexpr Register kSecondNonArgumentRegister = RBX;
   static constexpr Register kStackPointerRegister = SPREG;
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index f547c0b..38f1474 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -20,8 +20,8 @@
 static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
 
 // Both version numbers are inclusive.
-static const uint32_t kMinSupportedKernelFormatVersion = 52;
-static const uint32_t kMaxSupportedKernelFormatVersion = 52;
+static const uint32_t kMinSupportedKernelFormatVersion = 53;
+static const uint32_t kMaxSupportedKernelFormatVersion = 53;
 
 // Keep in sync with package:kernel/lib/binary/tag.dart
 #define KERNEL_TAG_LIST(V)                                                     \
@@ -42,6 +42,9 @@
   V(AssertInitializer, 12)                                                     \
   V(CheckLibraryIsLoaded, 13)                                                  \
   V(LoadLibrary, 14)                                                           \
+  V(EqualsNull, 15)                                                            \
+  V(EqualsCall, 16)                                                            \
+  V(StaticTearOff, 17)                                                         \
   V(ConstStaticInvocation, 18)                                                 \
   V(InvalidExpression, 19)                                                     \
   V(VariableGet, 20)                                                           \
@@ -126,6 +129,16 @@
   V(SimpleInterfaceType, 96)                                                   \
   V(SimpleFunctionType, 97)                                                    \
   V(ConstantExpression, 106)                                                   \
+  V(InstanceGet, 118)                                                          \
+  V(InstanceSet, 119)                                                          \
+  V(InstanceInvocation, 120)                                                   \
+  V(InstanceTearOff, 121)                                                      \
+  V(DynamicGet, 122)                                                           \
+  V(DynamicSet, 123)                                                           \
+  V(DynamicInvocation, 124)                                                    \
+  V(FunctionInvocation, 125)                                                   \
+  V(FunctionTearOff, 126)                                                      \
+  V(LocalFunctionInvocation, 127)                                              \
   V(SpecializedVariableGet, 128)                                               \
   V(SpecializedVariableSet, 136)                                               \
   V(SpecializedIntLiteral, 144)
@@ -191,6 +204,12 @@
 };
 
 // Keep in sync with package:kernel/lib/ast.dart
+enum MethodInvocationFlags {
+  kMethodInvocationFlagInvariant = 1 << 0,
+  kMethodInvocationFlagBoundsSafe = 1 << 1,
+};
+
+// Keep in sync with package:kernel/lib/ast.dart
 enum class NamedTypeFlags : uint8_t {
   kIsRequired = 1 << 0,
 };
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index acb3646..ed579f2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7145,6 +7145,14 @@
          kFfiHandleCid;
 }
 
+bool Function::FfiCSignatureReturnsStruct() const {
+  ASSERT(IsFfiTrampoline());
+  const Function& c_signature = Function::Handle(FfiCSignature());
+  const auto& return_type = AbstractType::Handle(c_signature.result_type());
+  const bool predefined = IsFfiTypeClassId(return_type.type_class_id());
+  return !predefined;
+}
+
 int32_t Function::FfiCallbackId() const {
   ASSERT(IsFfiTrampoline());
   const Object& obj = Object::Handle(raw_ptr()->data());
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 2a3b73d..802d6de 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2477,6 +2477,7 @@
   FunctionPtr FfiCSignature() const;
 
   bool FfiCSignatureContainsHandles() const;
+  bool FfiCSignatureReturnsStruct() const;
 
   // Can only be called on FFI trampolines.
   // -1 for Dart -> native calls.
diff --git a/runtime/vm/stack_frame_arm.h b/runtime/vm/stack_frame_arm.h
index eb8e104c..e79cc9c 100644
--- a/runtime/vm/stack_frame_arm.h
+++ b/runtime/vm/stack_frame_arm.h
@@ -68,6 +68,15 @@
 // kNativeCallbackTrampolineStackDelta must be added as well.
 constexpr intptr_t kCallbackSlotsBeforeSavedArguments = 2;
 
+// For FFI calls passing in TypedData, we save it on the stack before entering
+// a Dart frame. This denotes how to get to the backed up typed data.
+//
+// Note: This is not kCallerSpSlotFromFp on arm.
+//
+// [fp] holds callers fp, [fp+4] holds callers lr, [fp+8] is space for
+// return address, [fp+12] is our pushed TypedData pointer.
+static const int kFfiCallerTypedDataSlotFromFp = kCallerSpSlotFromFp + 1;
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_STACK_FRAME_ARM_H_
diff --git a/runtime/vm/stack_frame_arm64.h b/runtime/vm/stack_frame_arm64.h
index 3ede931..a487e67 100644
--- a/runtime/vm/stack_frame_arm64.h
+++ b/runtime/vm/stack_frame_arm64.h
@@ -67,6 +67,10 @@
 // kNativeCallbackTrampolineStackDelta must be added as well.
 constexpr intptr_t kCallbackSlotsBeforeSavedArguments = 2;
 
+// For FFI calls passing in TypedData, we save it on the stack before entering
+// a Dart frame. This denotes how to get to the backed up typed data.
+static const int kFfiCallerTypedDataSlotFromFp = kCallerSpSlotFromFp;
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_STACK_FRAME_ARM64_H_
diff --git a/runtime/vm/stack_frame_ia32.h b/runtime/vm/stack_frame_ia32.h
index 2c8edad..e1d16fe 100644
--- a/runtime/vm/stack_frame_ia32.h
+++ b/runtime/vm/stack_frame_ia32.h
@@ -57,6 +57,10 @@
 // kNativeCallbackTrampolineStackDelta must be added as well.
 constexpr intptr_t kCallbackSlotsBeforeSavedArguments = 0;
 
+// For FFI calls passing in TypedData, we save it on the stack before entering
+// a Dart frame. This denotes how to get to the backed up typed data.
+static const int kFfiCallerTypedDataSlotFromFp = kCallerSpSlotFromFp;
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_STACK_FRAME_IA32_H_
diff --git a/runtime/vm/stack_frame_x64.h b/runtime/vm/stack_frame_x64.h
index 835a2f5..fd6176b 100644
--- a/runtime/vm/stack_frame_x64.h
+++ b/runtime/vm/stack_frame_x64.h
@@ -68,6 +68,10 @@
 constexpr intptr_t kCallbackSlotsBeforeSavedArguments =
     2 + CallingConventions::kShadowSpaceBytes / kWordSize;
 
+// For FFI calls passing in TypedData, we save it on the stack before entering
+// a Dart frame. This denotes how to get to the backed up typed data.
+static const int kFfiCallerTypedDataSlotFromFp = kCallerSpSlotFromFp;
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_STACK_FRAME_X64_H_
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 1e408f1..5642b0a 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -425,6 +425,7 @@
   V(_Utf8Decoder, "_Utf8Decoder")                                              \
   V(_VariableMirror, "_VariableMirror")                                        \
   V(_WeakProperty, "_WeakProperty")                                            \
+  V(_addressOf, "_addressOf")                                                  \
   V(_classRangeCheck, "_classRangeCheck")                                      \
   V(_current, "_current")                                                      \
   V(_ensureScheduleImmediate, "_ensureScheduleImmediate")                      \
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 04b895a..0c29f31 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -79,6 +79,7 @@
       execution_state_(kThreadInNative),
       safepoint_state_(0),
       ffi_callback_code_(GrowableObjectArray::null()),
+      ffi_callback_stack_return_(TypedData::null()),
       api_top_scope_(NULL),
       task_kind_(kUnknownTask),
       dart_stream_(NULL),
@@ -641,6 +642,8 @@
   visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&active_stacktrace_));
   visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&sticky_error_));
   visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&ffi_callback_code_));
+  visitor->VisitPointer(
+      reinterpret_cast<ObjectPtr*>(&ffi_callback_stack_return_));
 
   // Visit the api local scope as it has all the api local handles.
   ApiLocalScope* scope = api_top_scope_;
@@ -1078,6 +1081,47 @@
   array.SetAt(callback_id, code);
 }
 
+void Thread::SetFfiCallbackStackReturn(int32_t callback_id,
+                                       intptr_t stack_return_delta) {
+#if defined(TARGET_ARCH_IA32)
+#else
+  UNREACHABLE();
+#endif
+
+  Zone* Z = Thread::Current()->zone();
+
+  /// In AOT the callback ID might have been allocated during compilation but
+  /// 'ffi_callback_code_' is initialized to empty again when the program
+  /// starts. Therefore we may need to initialize or expand it to accomodate
+  /// the callback ID.
+
+  if (ffi_callback_stack_return_ == TypedData::null()) {
+    ffi_callback_stack_return_ = TypedData::New(
+        kTypedDataInt8ArrayCid, kInitialCallbackIdsReserved, Heap::kOld);
+  }
+
+  auto& array = TypedData::Handle(Z, ffi_callback_stack_return_);
+
+  if (callback_id >= array.Length()) {
+    const int32_t capacity = array.Length();
+    if (callback_id >= capacity) {
+      // Ensure both that we grow enough and an exponential growth strategy.
+      const int32_t new_capacity =
+          Utils::Maximum(callback_id + 1, capacity * 2);
+      const auto& new_array = TypedData::Handle(
+          Z, TypedData::New(kTypedDataUint8ArrayCid, new_capacity, Heap::kOld));
+      for (intptr_t i = 0; i < capacity; i++) {
+        new_array.SetUint8(i, array.GetUint8(i));
+      }
+      array ^= new_array.raw();
+      ffi_callback_stack_return_ = new_array.raw();
+    }
+  }
+
+  ASSERT(callback_id < array.Length());
+  array.SetUint8(callback_id, stack_return_delta);
+}
+
 void Thread::VerifyCallbackIsolate(int32_t callback_id, uword entry) {
   NoSafepointScope _;
 
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index cc3c410..a882e0d 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -351,6 +351,10 @@
     return OFFSET_OF(Thread, ffi_callback_code_);
   }
 
+  static intptr_t callback_stack_return_offset() {
+    return OFFSET_OF(Thread, ffi_callback_stack_return_);
+  }
+
   // Tag state is maintained on transitions.
   enum {
     // Always true in generated state.
@@ -829,9 +833,17 @@
 
   // Store 'code' for the native callback identified by 'callback_id'.
   //
-  // Expands the callback code array as necessary to accomodate the callback ID.
+  // Expands the callback code array as necessary to accomodate the callback
+  // ID.
   void SetFfiCallbackCode(int32_t callback_id, const Code& code);
 
+  // Store 'stack_return' for the native callback identified by 'callback_id'.
+  //
+  // Expands the callback stack return array as necessary to accomodate the
+  // callback ID.
+  void SetFfiCallbackStackReturn(int32_t callback_id,
+                                 intptr_t stack_return_delta);
+
   // Ensure that 'callback_id' refers to a valid callback in this isolate.
   //
   // If "entry != 0", additionally checks that entry is inside the instructions
@@ -949,6 +961,7 @@
   uword execution_state_;
   std::atomic<uword> safepoint_state_;
   GrowableObjectArrayPtr ffi_callback_code_;
+  TypedDataPtr ffi_callback_stack_return_;
   uword exit_through_ffi_ = 0;
   ApiLocalScope* api_top_scope_;
 
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart
index b80c74e..2a991c9 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart
@@ -33,7 +33,7 @@
       f = value;
     } else if (value is Future) {
       f = _Future();
-      _Future._chainForeignFuture(value, f);
+      f._chainForeignFuture(value);
     } else {
       f = _Future.value(value);
     }
@@ -100,7 +100,7 @@
           if (value is _Future) {
             _Future._chainCoreFuture(value, asyncFuture);
           } else {
-            _Future._chainForeignFuture(value, asyncFuture);
+            asyncFuture._chainForeignFuture(value);
           }
         } else if (isRunningAsEvent) {
           asyncFuture._completeWithValue(JS('', '#', value));
@@ -356,7 +356,7 @@
       f = value;
     } else if (value is Future) {
       f = _Future();
-      _Future._chainForeignFuture(value, f);
+      f._chainForeignFuture(value);
     } else {
       f = _Future.value(value);
     }
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_number.dart b/sdk/lib/_internal/js_dev_runtime/private/js_number.dart
index fcaa2cd..5d6f6ac 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_number.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_number.dart
@@ -566,6 +566,7 @@
   // Returns gcd of abs(this) and abs(other).
   @notNull
   int gcd(@nullCheck int other) {
+    if (this is! int) throwArgumentErrorValue(this);
     int x = this.abs();
     int y = other.abs();
     if (x == 0) return y;
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index 862c871..335aedf 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -173,6 +173,11 @@
     assert(!handlesError);
     return _zone.run(_whenCompleteAction);
   }
+
+  // Whether the [value] future should be awaited and the [future] completed
+  // with its result, rather than just completing the [future] directly
+  // with the [value].
+  bool shouldChain(Future<dynamic> value) => value is Future<T> || value is! T;
 }
 
 class _Future<T> implements Future<T> {
@@ -457,27 +462,28 @@
     return prev;
   }
 
-  // Take the value (when completed) of source and complete target with that
+  // Take the value (when completed) of source and complete this future with that
   // value (or error). This function could chain all Futures, but is slower
   // for _Future than _chainCoreFuture, so you must use _chainCoreFuture
   // in that case.
-  static void _chainForeignFuture(Future source, _Future target) {
-    assert(!target._isComplete);
+  void _chainForeignFuture(Future source) {
+    assert(!_isComplete);
     assert(source is! _Future);
 
     // Mark the target as chained (and as such half-completed).
-    target._setPendingComplete();
+    _setPendingComplete();
     try {
       source.then((value) {
-        assert(target._isPendingComplete);
-        // The "value" may be another future if the foreign future
-        // implementation is mis-behaving,
-        // so use _complete instead of _completeWithValue.
-        target._clearPendingComplete(); // Clear this first, it's set again.
-        target._complete(value);
+        assert(_isPendingComplete);
+        _clearPendingComplete(); // Clear this first, it's set again.
+        try {
+          _completeWithValue(value as T);
+        } catch (error, stackTrace) {
+          _completeError(error, stackTrace);
+        }
       }, onError: (Object error, StackTrace stackTrace) {
-        assert(target._isPendingComplete);
-        target._completeError(error, stackTrace);
+        assert(_isPendingComplete);
+        _completeError(error, stackTrace);
       });
     } catch (e, s) {
       // This only happens if the `then` call threw synchronously when given
@@ -485,7 +491,7 @@
       // That requires a non-conforming implementation of the Future interface,
       // which should, hopefully, never happen.
       scheduleMicrotask(() {
-        target._completeError(e, s);
+        _completeError(e, s);
       });
     }
   }
@@ -514,7 +520,7 @@
       if (value is _Future<T>) {
         _chainCoreFuture(value, this);
       } else {
-        _chainForeignFuture(value, this);
+        _chainForeignFuture(value);
       }
     } else {
       _FutureListener? listeners = _removeListeners();
@@ -529,7 +535,6 @@
 
   void _completeWithValue(T value) {
     assert(!_isComplete);
-    assert(value is! Future<T>);
 
     _FutureListener? listeners = _removeListeners();
     _setValue(value);
@@ -589,7 +594,7 @@
       return;
     }
     // Just listen on the foreign future. This guarantees an async delay.
-    _chainForeignFuture(value, this);
+    _chainForeignFuture(value);
   }
 
   void _asyncCompleteError(Object error, StackTrace stackTrace) {
@@ -630,7 +635,7 @@
         nextListener = listener._nextListener;
       }
 
-      final sourceResult = source._resultOrListeners;
+      final dynamic sourceResult = source._resultOrListeners;
       // Do the actual propagation.
       // Set initial state of listenerHasError and listenerValueOrError. These
       // variables are updated with the outcome of potential callbacks.
@@ -740,9 +745,10 @@
         // If we changed zone, oldZone will not be null.
         if (oldZone != null) Zone._leave(oldZone);
 
-        // If the listener's value is a future we need to chain it. Note that
+        // If the listener's value is a future we *might* need to chain it. Note that
         // this can only happen if there is a callback.
-        if (listenerValueOrError is Future) {
+        if (listenerValueOrError is Future &&
+            listener.shouldChain(listenerValueOrError)) {
           Future chainSource = listenerValueOrError;
           // Shortcut if the chain-source is already completed. Just continue
           // the loop.
@@ -757,7 +763,7 @@
               _chainCoreFuture(chainSource, result);
             }
           } else {
-            _chainForeignFuture(chainSource, result);
+            result._chainForeignFuture(chainSource);
           }
           return;
         }
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 853cc32..b02678d 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -32,6 +32,7 @@
 
 [ $runtime != none && ($compiler == dart2js || $compiler == dartdevc || $compiler == dartdevk) ]
 int_parse_with_limited_ints_test: SkipByDesign # Requires fixed-size int64 support.
+integer_arith_vm_test: SkipByDesign # Is a VM optimization test that requires int64 support.
 iterable_return_type_int64_test: SkipByDesign # Requires int64 support.
 typed_data_with_limited_ints_test: SkipByDesign # Requires fixed-size int64 support.
 
diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status
index 5704e10..a4e1987 100644
--- a/tests/corelib_2/corelib_2.status
+++ b/tests/corelib_2/corelib_2.status
@@ -43,6 +43,7 @@
 
 [ $runtime != none && ($compiler == dart2js || $compiler == dartdevc || $compiler == dartdevk) ]
 int_parse_with_limited_ints_test: SkipByDesign # Requires fixed-size int64 support.
+integer_arith_vm_test: SkipByDesign # Is a VM optimization test that requires int64 support.
 iterable_return_type_int64_test: SkipByDesign # Requires int64 support.
 typed_data_with_limited_ints_test: SkipByDesign # Requires fixed-size int64 support.
 
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index 3baf069..37ab3e9 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -2,11 +2,6 @@
 # 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.
 
-# TODO(dartbug.com/36730): Implement structs by value.
-function_callbacks_structs_by_value_generated_test: Skip
-function_callbacks_structs_by_value_test: Skip
-function_structs_by_value_generated_test: Skip
-
 [ $builder_tag == msan ]
 vmspecific_handle_test: Skip # https://dartbug.com/42314
 
diff --git a/tests/ffi/vmspecific_static_checks_test.dart b/tests/ffi/vmspecific_static_checks_test.dart
index 8513885..b32acba 100644
--- a/tests/ffi/vmspecific_static_checks_test.dart
+++ b/tests/ffi/vmspecific_static_checks_test.dart
@@ -45,6 +45,12 @@
   testNativeFunctionSignatureInvalidOptionalNamed();
   testNativeFunctionSignatureInvalidOptionalPositional();
   testHandleVariance();
+  testEmptyStructLookupFunctionArgument();
+  testEmptyStructLookupFunctionReturn();
+  testEmptyStructAsFunctionArgument();
+  testEmptyStructAsFunctionReturn();
+  testEmptyStructFromFunctionArgument();
+  testEmptyStructFromFunctionReturn();
 }
 
 typedef Int8UnOp = Int8 Function(Int8);
@@ -476,3 +482,47 @@
   @Handle() //# 1002: compile-time error
   Object handle; //# 1002: compile-time error
 }
+
+class EmptyStruct extends Struct {}
+
+void testEmptyStructLookupFunctionArgument() {
+  testLibrary.lookupFunction< //# 1100: compile-time error
+      Void Function(EmptyStruct), //# 1100: compile-time error
+      void Function(EmptyStruct)>("DoesNotExist"); //# 1100: compile-time error
+}
+
+void testEmptyStructLookupFunctionReturn() {
+  testLibrary.lookupFunction< //# 1101: compile-time error
+      EmptyStruct Function(), //# 1101: compile-time error
+      EmptyStruct Function()>("DoesNotExist"); //# 1101: compile-time error
+}
+
+void testEmptyStructAsFunctionArgument() {
+  final pointer =
+      Pointer<NativeFunction<Void Function(EmptyStruct)>>.fromAddress(1234);
+  pointer.asFunction<void Function(EmptyStruct)>(); //# 1102: compile-time error
+}
+
+void testEmptyStructAsFunctionReturn() {
+  final pointer =
+      Pointer<NativeFunction<EmptyStruct Function()>>.fromAddress(1234);
+  pointer.asFunction<EmptyStruct Function()>(); //# 1103: compile-time error
+}
+
+void _consumeEmptyStruct(EmptyStruct e) {
+  print(e);
+}
+
+void testEmptyStructFromFunctionArgument() {
+  Pointer.fromFunction<Void Function(EmptyStruct)>(//# 1104: compile-time error
+      _consumeEmptyStruct); //# 1104: compile-time error
+}
+
+EmptyStruct _returnEmptyStruct() {
+  return EmptyStruct();
+}
+
+void testEmptyStructFromFunctionReturn() {
+  Pointer.fromFunction<EmptyStruct Function()>(//# 1105: compile-time error
+      _returnEmptyStruct); //# 1105: compile-time error
+}
diff --git a/tests/ffi_2/ffi_2.status b/tests/ffi_2/ffi_2.status
index 3baf069..37ab3e9 100644
--- a/tests/ffi_2/ffi_2.status
+++ b/tests/ffi_2/ffi_2.status
@@ -2,11 +2,6 @@
 # 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.
 
-# TODO(dartbug.com/36730): Implement structs by value.
-function_callbacks_structs_by_value_generated_test: Skip
-function_callbacks_structs_by_value_test: Skip
-function_structs_by_value_generated_test: Skip
-
 [ $builder_tag == msan ]
 vmspecific_handle_test: Skip # https://dartbug.com/42314
 
diff --git a/tests/ffi_2/vmspecific_static_checks_test.dart b/tests/ffi_2/vmspecific_static_checks_test.dart
index 5645c2a..dfa52a9 100644
--- a/tests/ffi_2/vmspecific_static_checks_test.dart
+++ b/tests/ffi_2/vmspecific_static_checks_test.dart
@@ -45,6 +45,12 @@
   testNativeFunctionSignatureInvalidOptionalNamed();
   testNativeFunctionSignatureInvalidOptionalPositional();
   testHandleVariance();
+  testEmptyStructLookupFunctionArgument();
+  testEmptyStructLookupFunctionReturn();
+  testEmptyStructAsFunctionArgument();
+  testEmptyStructAsFunctionReturn();
+  testEmptyStructFromFunctionArgument();
+  testEmptyStructFromFunctionReturn();
 }
 
 typedef Int8UnOp = Int8 Function(Int8);
@@ -476,3 +482,47 @@
   @Handle() //# 1002: compile-time error
   Object handle; //# 1002: compile-time error
 }
+
+class EmptyStruct extends Struct {}
+
+void testEmptyStructLookupFunctionArgument() {
+  testLibrary.lookupFunction< //# 1100: compile-time error
+      Void Function(EmptyStruct), //# 1100: compile-time error
+      void Function(EmptyStruct)>("DoesNotExist"); //# 1100: compile-time error
+}
+
+void testEmptyStructLookupFunctionReturn() {
+  testLibrary.lookupFunction< //# 1101: compile-time error
+      EmptyStruct Function(), //# 1101: compile-time error
+      EmptyStruct Function()>("DoesNotExist"); //# 1101: compile-time error
+}
+
+void testEmptyStructAsFunctionArgument() {
+  final pointer =
+      Pointer<NativeFunction<Void Function(EmptyStruct)>>.fromAddress(1234);
+  pointer.asFunction<void Function(EmptyStruct)>(); //# 1102: compile-time error
+}
+
+void testEmptyStructAsFunctionReturn() {
+  final pointer =
+      Pointer<NativeFunction<EmptyStruct Function()>>.fromAddress(1234);
+  pointer.asFunction<EmptyStruct Function()>(); //# 1103: compile-time error
+}
+
+void _consumeEmptyStruct(EmptyStruct e) {
+  print(e);
+}
+
+void testEmptyStructFromFunctionArgument() {
+  Pointer.fromFunction<Void Function(EmptyStruct)>(//# 1104: compile-time error
+      _consumeEmptyStruct); //# 1104: compile-time error
+}
+
+EmptyStruct _returnEmptyStruct() {
+  return EmptyStruct();
+}
+
+void testEmptyStructFromFunctionReturn() {
+  Pointer.fromFunction<EmptyStruct Function()>(//# 1105: compile-time error
+      _returnEmptyStruct); //# 1105: compile-time error
+}
diff --git a/tests/lib/async/future_future_test.dart b/tests/lib/async/future_future_test.dart
new file mode 100644
index 0000000..ab5e50b
--- /dev/null
+++ b/tests/lib/async/future_future_test.dart
@@ -0,0 +1,186 @@
+// 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.
+
+// Checks that `Future<Future<int>>` is a valid type
+// and that futures can contain and complete other futures.
+
+// This essentially checks that `FutureOr<X>` is treated correctly depending
+// on what `X` is.
+
+import 'dart:async';
+import 'package:async_helper/async_helper.dart';
+import "package:expect/expect.dart";
+
+main() {
+  asyncStart();
+
+  // Helper values and factories.
+  Future<Null> nullFuture = Future<Null>.value(null);
+
+  var stack = StackTrace.current;
+  var error = ArgumentError("yep");
+  Future<Null> errorFuture = Future<Null>.error(error, stack)
+    ..catchError((_) => null);
+  Future<int> fi(int n) => Future<int>.value(n);
+  Future<Future<int>> ffi(n) => Future<Future<int>>.value(fi(n));
+
+  // Tests that `Future<Future<int>>` can be created.
+  asyncTest(() {
+    return expectFutureFutureInt(ffi(0), 0);
+  });
+
+  // Check `Future.then`'s callback.
+
+  asyncTest(() {
+    Future<int> future = nullFuture.then<int>((_) => fi(1));
+    return expectFutureInt(future, 1);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> future = nullFuture.then<Future<int>>((_) => fi(2));
+    return expectFutureFutureInt(future, 2);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> future = nullFuture.then<Future<int>>((_) => ffi(3));
+    return expectFutureFutureInt(future, 3);
+  });
+
+  // Check `Future.then`'s `onError`.
+
+  asyncTest(() {
+    Future<int> future =
+        errorFuture.then<int>((_) => -1, onError: (_) => fi(4));
+    return expectFutureInt(future, 4);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> future =
+        errorFuture.then<Future<int>>((_) => fi(-1), onError: (_) => fi(5));
+    return expectFutureFutureInt(future, 5);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> future =
+        errorFuture.then<Future<int>>((_) => fi(-1), onError: (_) => ffi(6));
+    return expectFutureFutureInt(future, 6);
+  });
+
+  // Check `Future.catchError`.
+  // Its implied `FutureOr` return type is based on the original future's type.
+
+  asyncTest(() {
+    Future<int> errorFuture = Future<int>.error(error, stack);
+    Future<int> future = errorFuture.catchError((_) => fi(7));
+    return expectFutureInt(future, 7);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> errorFuture = Future<Future<int>>.error(error, stack);
+    Future<Future<int>> future = errorFuture.catchError((_) => fi(8));
+    return expectFutureFutureInt(future, 8);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> errorFuture = Future<Future<int>>.error(error, stack);
+    Future<Future<int>> future = errorFuture.catchError((_) => ffi(9));
+    return expectFutureFutureInt(future, 9);
+  });
+
+  // Check `Completer.complete`.
+
+  asyncTest(() {
+    var completer = Completer<int>()..complete(fi(10));
+    return expectFutureInt(completer.future, 10);
+  });
+
+  asyncTest(() {
+    var completer = Completer<Future<int>>()..complete(fi(11));
+    return expectFutureFutureInt(completer.future, 11);
+  });
+
+  asyncTest(() {
+    var completer = Completer<Future<int>>()..complete(ffi(12));
+    return expectFutureFutureInt(completer.future, 12);
+  });
+
+  // Future<Object> works correctly when Object is another Future.
+  asyncTest(() {
+    Future<Object> future = nullFuture.then<Object>((_) => fi(13));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    return future.then<void>((o) {
+      Expect.equals(13, o);
+    });
+  });
+
+  asyncTest(() {
+    Future<Object> future = nullFuture.then<Object>((_) => ffi(14));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    Expect.notType<Future<Future<int>>>(future);
+    return future.then<void>((v) => expectFutureInt(v, 14));
+  });
+
+  asyncTest(() {
+    Future<Object> future =
+        errorFuture.then<Object>((_) => -1, onError: (_) => fi(15));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    return future.then<void>((o) {
+      Expect.equals(15, o);
+    });
+  });
+
+  asyncTest(() {
+    Future<Object> future =
+        errorFuture.then<Object>((_) => -1, onError: (_) => ffi(16));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    Expect.notType<Future<Future<int>>>(future);
+    return future.then<void>((v) => expectFutureInt(v, 16));
+  });
+
+  asyncTest(() {
+    Future<Object> errorFuture = Future<Object>.error(error, stack);
+    Future<Object> future = errorFuture.catchError((_) => fi(17));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    return future.then<void>((o) {
+      Expect.equals(17, o);
+    });
+  });
+
+  asyncTest(() {
+    Future<Object> errorFuture = Future<Object>.error(error, stack);
+    Future<Object> future = errorFuture.catchError((_) => ffi(18));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    Expect.notType<Future<Future<int>>>(future);
+    return future.then<void>((v) => expectFutureInt(v, 18));
+  });
+
+  asyncEnd();
+}
+
+// Checks that future is a Future<Future<int>> containing the value Future<int>
+// which then contains the value 42.
+Future<void> expectFutureFutureInt(dynamic future, int n) {
+  Expect.type<Future<Future<int>>>(future);
+  asyncStart();
+  return future.then<void>((dynamic v) {
+    Expect.type<Future<int>>(v, "$n");
+    return expectFutureInt(v, n).then(asyncSuccess);
+  });
+}
+
+Future<void> expectFutureInt(dynamic future, int n) {
+  Expect.type<Future<int>>(future);
+  asyncStart();
+  return future.then<void>((dynamic v) {
+    Expect.type<int>(v, "$n");
+    Expect.equals(n, v);
+    asyncEnd();
+  });
+}
diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart
index f2d9710..8fc947b 100644
--- a/tests/lib/async/future_test.dart
+++ b/tests/lib/async/future_test.dart
@@ -1094,7 +1094,7 @@
     var f = new UglyFuture(5);
     // Sanity check that our future is as mis-behaved as we think.
     f.then((v) {
-      Expect.isTrue(v is Future);
+      Expect.equals(UglyFuture(4), v);
     });
 
     var v = await f;
@@ -1102,13 +1102,11 @@
     // suggests that it flattens. In practice it currently doesn't.
     // The specification doesn't say anything special, so v should be the
     // completion value of the UglyFuture future which is a future.
-    Expect.isTrue(v is Future);
+    Expect.equals(UglyFuture(4), v);
 
-    // This used to hit an assert in checked mode.
-    // The CL adding this test changed the behavior to actually flatten the
-    // the future returned by the then-callback.
+    // We no longer flatten recursively when completing a future.
     var w = new Future.value(42).then((_) => f);
-    Expect.equals(42, await w);
+    Expect.equals(UglyFuture(4), await w);
     asyncEnd();
   }();
 }
@@ -1259,8 +1257,10 @@
 // An evil future that completes with another future.
 class UglyFuture implements Future<dynamic> {
   final _result;
+  final int _badness;
   UglyFuture(int badness)
-      : _result = (badness == 0) ? 42 : new UglyFuture(badness - 1);
+      : _badness = badness,
+        _result = (badness == 0) ? 42 : new UglyFuture(badness - 1);
   Future<S> then<S>(action(value), {Function? onError}) {
     var c = new Completer<S>();
     c.complete(new Future<S>.microtask(() => action(_result)));
@@ -1282,4 +1282,10 @@
   Future timeout(Duration duration, {onTimeout()?}) {
     return this;
   }
+
+  int get hashCode => _badness;
+  bool operator ==(Object other) =>
+      other is UglyFuture && _badness == other._badness;
+
+  String toString() => "UglyFuture($_badness)";
 }
diff --git a/tests/lib_2/async/future_future_test.dart b/tests/lib_2/async/future_future_test.dart
new file mode 100644
index 0000000..45aaf82
--- /dev/null
+++ b/tests/lib_2/async/future_future_test.dart
@@ -0,0 +1,187 @@
+// 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.
+
+// Checks that Future<Future<int>> is a valid type and that futures can contain
+// and complete other futures.
+
+// This essentially checks that `FutureOr<X>` is treated correctly depending
+// on what `X` is.
+
+import 'dart:async';
+import 'package:async_helper/async_helper.dart';
+import "package:expect/expect.dart";
+
+main() {
+  asyncStart();
+
+  // Helper values.
+  Future<Null> nullFuture = Future<Null>.value(null);
+
+  var stack = StackTrace.current;
+  var error = ArgumentError("yep");
+  Future<Null> errorFuture = Future<Null>.error(error, stack)
+    ..catchError((_) => null);
+  Future<int> fi(int n) => Future<int>.value(n);
+
+  // Tests that Future<Future<int>> can be created.
+  Future<Future<int>> ffi(n) => Future<Future<int>>.value(fi(n));
+
+  asyncTest(() {
+    return expectFutureFutureInt(ffi(0), 0);
+  });
+
+  // Check `Future.then`'s callback.
+
+  asyncTest(() {
+    Future<int> future = nullFuture.then<int>((_) => fi(1));
+    return expectFutureInt(future, 1);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> future = nullFuture.then<Future<int>>((_) => fi(2));
+    return expectFutureFutureInt(future, 2);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> future = nullFuture.then<Future<int>>((_) => ffi(3));
+    return expectFutureFutureInt(future, 3);
+  });
+
+  // Check `Future.then`'s `onError`.
+
+  asyncTest(() {
+    Future<int> future =
+        errorFuture.then<int>((_) => -1, onError: (_) => fi(4));
+    return expectFutureInt(future, 4);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> future =
+        errorFuture.then<Future<int>>((_) => fi(-1), onError: (_) => fi(5));
+    return expectFutureFutureInt(future, 5);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> future =
+        errorFuture.then<Future<int>>((_) => fi(-1), onError: (_) => ffi(6));
+    return expectFutureFutureInt(future, 6);
+  });
+
+  // Checkc Future.catchError, it's FutureOr is based on the
+  // original future's type.
+
+  asyncTest(() {
+    Future<int> errorFuture = Future<int>.error(error, stack);
+    Future<int> future = errorFuture.catchError((_) => fi(7));
+    return expectFutureInt(future, 7);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> errorFuture = Future<Future<int>>.error(error, stack);
+    Future<Future<int>> future = errorFuture.catchError((_) => fi(8));
+    return expectFutureFutureInt(future, 8);
+  });
+
+  asyncTest(() {
+    Future<Future<int>> errorFuture = Future<Future<int>>.error(error, stack);
+    Future<Future<int>> future = errorFuture.catchError((_) => ffi(9));
+    return expectFutureFutureInt(future, 9);
+  });
+
+  // Check Completer.complete.
+
+  asyncTest(() {
+    var completer = Completer<int>()..complete(fi(10));
+    return expectFutureInt(completer.future, 10);
+  });
+
+  asyncTest(() {
+    var completer = Completer<Future<int>>()..complete(fi(11));
+    return expectFutureFutureInt(completer.future, 11);
+  });
+
+  asyncTest(() {
+    var completer = Completer<Future<int>>()..complete(ffi(12));
+    return expectFutureFutureInt(completer.future, 12);
+  });
+
+  // Future<Object> works correctly when Object is another Future.
+  asyncTest(() {
+    Future<Object> future = nullFuture.then<Object>((_) => fi(13));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    return future.then<void>((o) {
+      Expect.equals(13, o);
+    });
+  });
+
+  asyncTest(() {
+    Future<Object> future = nullFuture.then<Object>((_) => ffi(14));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    Expect.notType<Future<Future<int>>>(future);
+    return future.then<void>((v) => expectFutureInt(v, 14));
+  });
+
+  asyncTest(() {
+    Future<Object> future =
+        errorFuture.then<Object>((_) => -1, onError: (_) => fi(15));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    return future.then<void>((o) {
+      Expect.equals(15, o);
+    });
+  });
+
+  asyncTest(() {
+    Future<Object> future =
+        errorFuture.then<Object>((_) => -1, onError: (_) => ffi(16));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    Expect.notType<Future<Future<int>>>(future);
+    return future.then<void>((v) => expectFutureInt(v, 16));
+  });
+
+  asyncTest(() {
+    Future<Object> errorFuture = Future<Object>.error(error, stack);
+    Future<Object> future = errorFuture.catchError((_) => fi(17));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    return future.then<void>((o) {
+      Expect.equals(17, o);
+    });
+  });
+
+  asyncTest(() {
+    Future<Object> errorFuture = Future<Object>.error(error, stack);
+    Future<Object> future = errorFuture.catchError((_) => ffi(18));
+    Expect.type<Future<Object>>(future);
+    Expect.notType<Future<int>>(future);
+    Expect.notType<Future<Future<int>>>(future);
+    return future.then<void>((v) => expectFutureInt(v, 18));
+  });
+
+  asyncEnd();
+}
+
+// Checks that future is a Future<Future<int>> containing the value Future<int>
+// which then contains the value 42.
+Future<void> expectFutureFutureInt(dynamic future, int n) {
+  Expect.type<Future<Future<int>>>(future);
+  asyncStart();
+  return future.then<void>((dynamic v) {
+    Expect.type<Future<int>>(v, "$n");
+    return expectFutureInt(v, n).then(asyncSuccess);
+  });
+}
+
+Future<void> expectFutureInt(dynamic future, int n) {
+  Expect.type<Future<int>>(future);
+  asyncStart();
+  return future.then<void>((dynamic v) {
+    Expect.type<int>(v, "$n");
+    Expect.equals(n, v);
+    asyncEnd();
+  });
+}
diff --git a/tests/lib_2/async/future_test.dart b/tests/lib_2/async/future_test.dart
index 2e546bf..9242649 100644
--- a/tests/lib_2/async/future_test.dart
+++ b/tests/lib_2/async/future_test.dart
@@ -1087,7 +1087,7 @@
     var f = new UglyFuture(5);
     // Sanity check that our future is as mis-behaved as we think.
     f.then((v) {
-      Expect.isTrue(v is Future);
+      Expect.equals(UglyFuture(4), v);
     });
 
     var v = await f;
@@ -1095,13 +1095,11 @@
     // suggests that it flattens. In practice it currently doesn't.
     // The specification doesn't say anything special, so v should be the
     // completion value of the UglyFuture future which is a future.
-    Expect.isTrue(v is Future);
+    Expect.equals(UglyFuture(4), v);
 
-    // This used to hit an assert in checked mode.
-    // The CL adding this test changed the behavior to actually flatten the
-    // the future returned by the then-callback.
+    // We no longer flatten recursively in situations like this.
     var w = new Future.value(42).then((_) => f);
-    Expect.equals(42, await w);
+    Expect.equals(UglyFuture(4), await w);
     asyncEnd();
   }();
 }
@@ -1253,11 +1251,13 @@
 // An evil future that completes with another future.
 class UglyFuture implements Future<dynamic> {
   final _result;
+  final int _badness;
   UglyFuture(int badness)
-      : _result = (badness == 0) ? 42 : new UglyFuture(badness - 1);
+      : _badness = badness,
+        _result = (badness == 0) ? 42 : new UglyFuture(badness - 1);
   Future<S> then<S>(action(value), {Function onError}) {
     var c = new Completer<S>();
-    c.complete(new Future.microtask(() => action(_result)));
+    c.complete(new Future<S>.microtask(() => action(_result)));
     return c.future;
   }
 
@@ -1276,4 +1276,10 @@
   Future timeout(Duration duration, {onTimeout()}) {
     return this;
   }
+
+  int get hashCode => _badness;
+  bool operator ==(Object other) =>
+      other is UglyFuture && _badness == other._badness;
+
+  String toString() => "UglyFuture($_badness)";
 }
diff --git a/tools/VERSION b/tools/VERSION
index 583b5c1..4576f76 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 149
+PRERELEASE 150
 PRERELEASE_PATCH 0
\ No newline at end of file