Version 2.13.0-51.0.dev

Merge commit '8467186ca0aa1d2b716ed00cb9bc55f74d9ddda9' into 'dev'
diff --git a/pkg/compiler/lib/src/ir/constants.dart b/pkg/compiler/lib/src/ir/constants.dart
index d1ddfd7..861711b 100644
--- a/pkg/compiler/lib/src/ir/constants.dart
+++ b/pkg/compiler/lib/src/ir/constants.dart
@@ -204,11 +204,21 @@
   }
 
   @override
+  R accept1<R, A>(ir.TreeVisitor1<R, A> v, A arg) {
+    throw new UnsupportedError("ConstantReference.accept");
+  }
+
+  @override
   transformChildren(ir.Transformer v) {
     throw new UnsupportedError("ConstantReference.transformChildren");
   }
 
   @override
+  transformOrRemoveChildren(ir.RemovingTransformer v) {
+    throw new UnsupportedError("ConstantReference.transformOrRemoveChildren");
+  }
+
+  @override
   int get hashCode => 13 * constant.hashCode;
 
   @override
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 958d410..101244f 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -15,7 +15,8 @@
 import 'package:kernel/binary/ast_to_binary.dart' as kernel show BinaryPrinter;
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
-import 'package:kernel/kernel.dart' hide MapEntry;
+import 'package:kernel/kernel.dart';
+import 'package:kernel/ast.dart' show NonNullableByDefaultCompiledMode;
 import 'package:kernel/target/targets.dart';
 import 'package:kernel/text/ast_to_text.dart' as kernel show Printer;
 import 'package:path/path.dart' as p;
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index 81fadbf..8318288 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -5,7 +5,6 @@
 // @dart = 2.9
 
 import 'dart:collection';
-import 'dart:core' hide MapEntry;
 
 import 'package:_fe_analyzer_shared/src/messages/codes.dart'
     show Message, LocatedMessage;
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
index b98d56b..432df8c 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
 
 import 'package:kernel/ast.dart';
diff --git a/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart b/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
index 0ba64f4..ed02387 100644
--- a/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 
 import '../messages.dart';
diff --git a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
index 84205dc..79c6bc6 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 import 'package:kernel/core_types.dart';
 
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 736be55..1fe24be 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -8,7 +8,7 @@
 
 import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/src/legacy_erasure.dart';
 
diff --git a/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart
index 3f91098..b0ba617 100644
--- a/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.9
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 
 import '../problems.dart';
 import 'library_builder.dart';
diff --git a/pkg/front_end/lib/src/fasta/builder/function_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
index 4bdfca5..b938323 100644
--- a/pkg/front_end/lib/src/fasta/builder/function_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
@@ -6,8 +6,6 @@
 
 library fasta.procedure_builder;
 
-import 'dart:core' hide MapEntry;
-
 import 'package:front_end/src/fasta/kernel/kernel_api.dart';
 import 'package:kernel/ast.dart';
 
diff --git a/pkg/front_end/lib/src/fasta/builder/member_builder.dart b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
index f496386..51ee376 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -6,8 +6,6 @@
 
 library fasta.member_builder;
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 import 'package:kernel/core_types.dart';
 
diff --git a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
index 0678910..6004b66 100644
--- a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
@@ -8,7 +8,7 @@
 
 import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 
 import '../fasta_codes.dart'
     show
diff --git a/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart b/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
index d14f2dc..4270ba8 100644
--- a/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 
 import '../kernel/body_builder.dart';
diff --git a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
index cecc308..c7b250b 100644
--- a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:front_end/src/fasta/dill/dill_member_builder.dart';
 import 'package:front_end/src/fasta/kernel/kernel_api.dart';
 import 'package:kernel/ast.dart';
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
index 93ee939..ea2e411 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
@@ -6,7 +6,7 @@
 
 library fasta.dill_class_builder;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 
 import '../builder/class_builder.dart';
 import '../builder/library_builder.dart';
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
index b460387..ea03898 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 
 import '../builder/extension_builder.dart';
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart
index d946f72..d12400f 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 
 import '../builder/builder.dart';
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index bedea60..6809bc9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -6,10 +6,7 @@
 
 library fasta.body_builder;
 
-import 'dart:core' hide MapEntry;
-
-import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart'
-    hide Reference; // Work around https://github.com/dart-lang/sdk/issues/44667
+import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
 
 import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
 
@@ -43,8 +40,7 @@
 
 import 'package:_fe_analyzer_shared/src/util/link.dart';
 
-import 'package:kernel/ast.dart'
-    hide Reference; // Work around https://github.com/dart-lang/sdk/issues/44667
+import 'package:kernel/ast.dart';
 import 'package:kernel/type_environment.dart';
 
 import '../builder/builder.dart';
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index b97967d..25e0a70 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -6,7 +6,7 @@
 
 library fasta.class_hierarchy_builder;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/class_hierarchy.dart'
     show ClassHierarchy, ClassHierarchyBase;
diff --git a/pkg/front_end/lib/src/fasta/kernel/collections.dart b/pkg/front_end/lib/src/fasta/kernel/collections.dart
index 1e2f994..5a055f9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/collections.dart
@@ -6,21 +6,7 @@
 
 library fasta.collections;
 
-import 'dart:core' hide MapEntry;
-
-import 'package:kernel/ast.dart'
-    show
-        DartType,
-        Expression,
-        ExpressionStatement,
-        MapEntry,
-        NullLiteral,
-        Statement,
-        TreeNode,
-        VariableDeclaration,
-        setParents,
-        transformList,
-        visitList;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/src/printer.dart';
 
@@ -92,14 +78,22 @@
   }
 
   @override
-  visitChildren(Visitor<Object> v) {
+  void visitChildren(Visitor<Object> v) {
     expression?.accept(v);
   }
 
   @override
-  transformChildren(Transformer v) {
+  void transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
+      expression = v.transform(expression);
+      expression?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (expression != null) {
+      expression = v.transformOrRemoveExpression(expression);
       expression?.parent = this;
     }
   }
@@ -138,24 +132,40 @@
   }
 
   @override
-  visitChildren(Visitor<Object> v) {
+  void visitChildren(Visitor<Object> v) {
     condition?.accept(v);
     then?.accept(v);
     otherwise?.accept(v);
   }
 
   @override
-  transformChildren(Transformer v) {
+  void transformChildren(Transformer v) {
     if (condition != null) {
-      condition = condition.accept<TreeNode>(v);
+      condition = v.transform(condition);
       condition?.parent = this;
     }
     if (then != null) {
-      then = then.accept<TreeNode>(v);
+      then = v.transform(then);
       then?.parent = this;
     }
     if (otherwise != null) {
-      otherwise = otherwise.accept<TreeNode>(v);
+      otherwise = v.transform(otherwise);
+      otherwise?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (condition != null) {
+      condition = v.transformOrRemoveExpression(condition);
+      condition?.parent = this;
+    }
+    if (then != null) {
+      then = v.transformOrRemoveExpression(then);
+      then?.parent = this;
+    }
+    if (otherwise != null) {
+      otherwise = v.transformOrRemoveExpression(otherwise);
       otherwise?.parent = this;
     }
   }
@@ -213,7 +223,7 @@
   }
 
   @override
-  visitChildren(Visitor<Object> v) {
+  void visitChildren(Visitor<Object> v) {
     visitList(variables, v);
     condition?.accept(v);
     visitList(updates, v);
@@ -221,15 +231,29 @@
   }
 
   @override
-  transformChildren(Transformer v) {
-    transformList(variables, v, this);
+  void transformChildren(Transformer v) {
+    v.transformList(variables, this);
     if (condition != null) {
-      condition = condition.accept<TreeNode>(v);
+      condition = v.transform(condition);
       condition?.parent = this;
     }
-    transformList(updates, v, this);
+    v.transformList(updates, this);
     if (body != null) {
-      body = body.accept<TreeNode>(v);
+      body = v.transform(body);
+      body?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformVariableDeclarationList(variables, this);
+    if (condition != null) {
+      condition = v.transformOrRemoveExpression(condition);
+      condition?.parent = this;
+    }
+    v.transformExpressionList(updates, this);
+    if (body != null) {
+      body = v.transformOrRemoveExpression(body);
       body?.parent = this;
     }
   }
@@ -286,7 +310,7 @@
         ..fileOffset = syntheticAssignment.fileOffset)
       : expressionEffects;
 
-  visitChildren(Visitor<Object> v) {
+  void visitChildren(Visitor<Object> v) {
     variable?.accept(v);
     iterable?.accept(v);
     syntheticAssignment?.accept(v);
@@ -295,29 +319,57 @@
     problem?.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  void transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
+      variable = v.transform(variable);
       variable?.parent = this;
     }
     if (iterable != null) {
-      iterable = iterable.accept<TreeNode>(v);
+      iterable = v.transform(iterable);
       iterable?.parent = this;
     }
     if (syntheticAssignment != null) {
-      syntheticAssignment = syntheticAssignment.accept<TreeNode>(v);
+      syntheticAssignment = v.transform(syntheticAssignment);
       syntheticAssignment?.parent = this;
     }
     if (expressionEffects != null) {
-      expressionEffects = expressionEffects.accept<TreeNode>(v);
+      expressionEffects = v.transform(expressionEffects);
       expressionEffects?.parent = this;
     }
     if (body != null) {
-      body = body.accept<TreeNode>(v);
+      body = v.transform(body);
       body?.parent = this;
     }
     if (problem != null) {
-      problem = problem.accept<TreeNode>(v);
+      problem = v.transform(problem);
+      problem?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (variable != null) {
+      variable = v.transformOrRemoveVariableDeclaration(variable);
+      variable?.parent = this;
+    }
+    if (iterable != null) {
+      iterable = v.transformOrRemoveExpression(iterable);
+      iterable?.parent = this;
+    }
+    if (syntheticAssignment != null) {
+      syntheticAssignment = v.transformOrRemoveExpression(syntheticAssignment);
+      syntheticAssignment?.parent = this;
+    }
+    if (expressionEffects != null) {
+      expressionEffects = v.transformOrRemoveStatement(expressionEffects);
+      expressionEffects?.parent = this;
+    }
+    if (body != null) {
+      body = v.transformOrRemoveExpression(body);
+      body?.parent = this;
+    }
+    if (problem != null) {
+      problem = v.transformOrRemoveExpression(problem);
       problem?.parent = this;
     }
   }
@@ -374,6 +426,9 @@
   R accept<R>(TreeVisitor<R> v) => v.defaultTreeNode(this);
 
   @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.defaultTreeNode(this, arg);
+
+  @override
   String toStringInternal() => toText(defaultAstTextStrategy);
 
   @override
@@ -400,14 +455,22 @@
   }
 
   @override
-  visitChildren(Visitor<Object> v) {
+  void visitChildren(Visitor<Object> v) {
     expression?.accept(v);
   }
 
   @override
-  transformChildren(Transformer v) {
+  void transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
+      expression = v.transform(expression);
+      expression?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (expression != null) {
+      expression = v.transformOrRemoveExpression(expression);
       expression?.parent = this;
     }
   }
@@ -436,24 +499,40 @@
   }
 
   @override
-  visitChildren(Visitor<Object> v) {
+  void visitChildren(Visitor<Object> v) {
     condition?.accept(v);
     then?.accept(v);
     otherwise?.accept(v);
   }
 
   @override
-  transformChildren(Transformer v) {
+  void transformChildren(Transformer v) {
     if (condition != null) {
-      condition = condition.accept<TreeNode>(v);
+      condition = v.transform(condition);
       condition?.parent = this;
     }
     if (then != null) {
-      then = then.accept<TreeNode>(v);
+      then = v.transform(then);
       then?.parent = this;
     }
     if (otherwise != null) {
-      otherwise = otherwise.accept<TreeNode>(v);
+      otherwise = v.transform(otherwise);
+      otherwise?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (condition != null) {
+      condition = v.transformOrRemoveExpression(condition);
+      condition?.parent = this;
+    }
+    if (then != null) {
+      then = v.transformOrRemove(then, dummyMapEntry);
+      then?.parent = this;
+    }
+    if (otherwise != null) {
+      otherwise = v.transformOrRemove(otherwise, dummyMapEntry);
       otherwise?.parent = this;
     }
   }
@@ -484,7 +563,7 @@
   }
 
   @override
-  visitChildren(Visitor<Object> v) {
+  void visitChildren(Visitor<Object> v) {
     visitList(variables, v);
     condition?.accept(v);
     visitList(updates, v);
@@ -492,15 +571,29 @@
   }
 
   @override
-  transformChildren(Transformer v) {
-    transformList(variables, v, this);
+  void transformChildren(Transformer v) {
+    v.transformList(variables, this);
     if (condition != null) {
-      condition = condition.accept<TreeNode>(v);
+      condition = v.transform(condition);
       condition?.parent = this;
     }
-    transformList(updates, v, this);
+    v.transformList(updates, this);
     if (body != null) {
-      body = body.accept<TreeNode>(v);
+      body = v.transform(body);
+      body?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformVariableDeclarationList(variables, this);
+    if (condition != null) {
+      condition = v.transformOrRemoveExpression(condition);
+      condition?.parent = this;
+    }
+    v.transformExpressionList(updates, this);
+    if (body != null) {
+      body = v.transformOrRemove(body, dummyMapEntry);
       body?.parent = this;
     }
   }
@@ -543,7 +636,7 @@
         ..fileOffset = syntheticAssignment.fileOffset)
       : expressionEffects;
 
-  visitChildren(Visitor<Object> v) {
+  void visitChildren(Visitor<Object> v) {
     variable?.accept(v);
     iterable?.accept(v);
     syntheticAssignment?.accept(v);
@@ -552,29 +645,57 @@
     problem?.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  void transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
+      variable = v.transform(variable);
       variable?.parent = this;
     }
     if (iterable != null) {
-      iterable = iterable.accept<TreeNode>(v);
+      iterable = v.transform(iterable);
       iterable?.parent = this;
     }
     if (syntheticAssignment != null) {
-      syntheticAssignment = syntheticAssignment.accept<TreeNode>(v);
+      syntheticAssignment = v.transform(syntheticAssignment);
       syntheticAssignment?.parent = this;
     }
     if (expressionEffects != null) {
-      expressionEffects = expressionEffects.accept<TreeNode>(v);
+      expressionEffects = v.transform(expressionEffects);
       expressionEffects?.parent = this;
     }
     if (body != null) {
-      body = body.accept<TreeNode>(v);
+      body = v.transform(body);
       body?.parent = this;
     }
     if (problem != null) {
-      problem = problem.accept<TreeNode>(v);
+      problem = v.transform(problem);
+      problem?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (variable != null) {
+      variable = v.transformOrRemoveVariableDeclaration(variable);
+      variable?.parent = this;
+    }
+    if (iterable != null) {
+      iterable = v.transformOrRemoveExpression(iterable);
+      iterable?.parent = this;
+    }
+    if (syntheticAssignment != null) {
+      syntheticAssignment = v.transformOrRemoveExpression(syntheticAssignment);
+      syntheticAssignment?.parent = this;
+    }
+    if (expressionEffects != null) {
+      expressionEffects = v.transformOrRemoveStatement(expressionEffects);
+      expressionEffects?.parent = this;
+    }
+    if (body != null) {
+      body = v.transformOrRemove(body, dummyMapEntry);
+      body?.parent = this;
+    }
+    if (problem != null) {
+      problem = v.transformOrRemoveExpression(problem);
       problem?.parent = this;
     }
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart b/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
index 641352a..86496d4 100644
--- a/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.9
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchyBase;
 
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 2f96cfa..9709c98 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -20,8 +20,6 @@
 /// language.  Issue(http://dartbug.com/31799)
 library fasta.constant_evaluator;
 
-import 'dart:core' hide MapEntry;
-
 import 'dart:io' as io;
 
 import 'package:kernel/ast.dart';
@@ -157,7 +155,7 @@
       typeEnvironment,
       errorReporter,
       evaluationMode);
-  constantsTransformer.visitProcedure(procedure);
+  constantsTransformer.visitProcedure(procedure, null);
 }
 
 enum EvaluationMode {
@@ -329,7 +327,7 @@
   Constant visitUnevaluatedConstant(UnevaluatedConstant node) => null;
 }
 
-class ConstantsTransformer extends Transformer {
+class ConstantsTransformer extends RemovingTransformer {
   final ConstantsBackend backend;
   final ConstantEvaluator constantEvaluator;
   final TypeEnvironment typeEnvironment;
@@ -369,12 +367,12 @@
 
     transformAnnotations(library.annotations, library);
 
-    transformList(library.dependencies, this, library);
-    transformList(library.parts, this, library);
-    transformList(library.typedefs, this, library);
-    transformList(library.classes, this, library);
-    transformList(library.procedures, this, library);
-    transformList(library.fields, this, library);
+    transformLibraryDependencyList(library.dependencies, library);
+    transformLibraryPartList(library.parts, library);
+    transformTypedefList(library.typedefs, library);
+    transformClassList(library.classes, library);
+    transformProcedureList(library.procedures, library);
+    transformFieldList(library.fields, library);
 
     if (!keepFields) {
       // The transformer API does not iterate over `Library.additionalExports`,
@@ -387,7 +385,7 @@
   }
 
   @override
-  LibraryPart visitLibraryPart(LibraryPart node) {
+  LibraryPart visitLibraryPart(LibraryPart node, TreeNode removalSentinel) {
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
     });
@@ -395,7 +393,8 @@
   }
 
   @override
-  LibraryDependency visitLibraryDependency(LibraryDependency node) {
+  LibraryDependency visitLibraryDependency(
+      LibraryDependency node, TreeNode removalSentinel) {
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
     });
@@ -403,78 +402,80 @@
   }
 
   @override
-  Class visitClass(Class node) {
+  Class visitClass(Class node, TreeNode removalSentinel) {
     StaticTypeContext oldStaticTypeContext = _staticTypeContext;
     _staticTypeContext = new StaticTypeContext.forAnnotations(
         node.enclosingLibrary, typeEnvironment);
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
-      transformList(node.fields, this, node);
-      transformList(node.typeParameters, this, node);
-      transformList(node.constructors, this, node);
-      transformList(node.procedures, this, node);
-      transformList(node.redirectingFactoryConstructors, this, node);
+      transformFieldList(node.fields, node);
+      transformTypeParameterList(node.typeParameters, node);
+      transformConstructorList(node.constructors, node);
+      transformProcedureList(node.procedures, node);
+      transformRedirectingFactoryConstructorList(
+          node.redirectingFactoryConstructors, node);
     });
     _staticTypeContext = oldStaticTypeContext;
     return node;
   }
 
   @override
-  Procedure visitProcedure(Procedure node) {
+  Procedure visitProcedure(Procedure node, TreeNode removalSentinel) {
     StaticTypeContext oldStaticTypeContext = _staticTypeContext;
     _staticTypeContext = new StaticTypeContext(node, typeEnvironment);
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
-      node.function = node.function.accept<TreeNode>(this)..parent = node;
+      node.function = transform(node.function)..parent = node;
     });
     _staticTypeContext = oldStaticTypeContext;
     return node;
   }
 
   @override
-  Constructor visitConstructor(Constructor node) {
+  Constructor visitConstructor(Constructor node, TreeNode removalSentinel) {
     StaticTypeContext oldStaticTypeContext = _staticTypeContext;
     _staticTypeContext = new StaticTypeContext(node, typeEnvironment);
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
-      transformList(node.initializers, this, node);
-      node.function = node.function.accept<TreeNode>(this)..parent = node;
+      transformInitializerList(node.initializers, node);
+      node.function = transform(node.function)..parent = node;
     });
     _staticTypeContext = oldStaticTypeContext;
     return node;
   }
 
   @override
-  Typedef visitTypedef(Typedef node) {
+  Typedef visitTypedef(Typedef node, TreeNode removalSentinel) {
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
-      transformList(node.typeParameters, this, node);
-      transformList(node.typeParametersOfFunctionType, this, node);
-      transformList(node.positionalParameters, this, node);
-      transformList(node.namedParameters, this, node);
+      transformTypeParameterList(node.typeParameters, node);
+      transformTypeParameterList(node.typeParametersOfFunctionType, node);
+      transformVariableDeclarationList(node.positionalParameters, node);
+      transformVariableDeclarationList(node.namedParameters, node);
     });
     return node;
   }
 
   @override
   RedirectingFactoryConstructor visitRedirectingFactoryConstructor(
-      RedirectingFactoryConstructor node) {
+      RedirectingFactoryConstructor node, TreeNode removalSentinel) {
     // Currently unreachable as the compiler doesn't produce
     // RedirectingFactoryConstructor.
     StaticTypeContext oldStaticTypeContext = _staticTypeContext;
     _staticTypeContext = new StaticTypeContext(node, typeEnvironment);
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
-      transformList(node.typeParameters, this, node);
-      transformList(node.positionalParameters, this, node);
-      transformList(node.namedParameters, this, node);
+      transformTypeParameterList(node.typeParameters, node);
+      transformVariableDeclarationList(node.positionalParameters, node);
+      transformVariableDeclarationList(node.namedParameters, node);
     });
     _staticTypeContext = oldStaticTypeContext;
     return node;
   }
 
   @override
-  TypeParameter visitTypeParameter(TypeParameter node) {
+  TypeParameter visitTypeParameter(
+      TypeParameter node, TreeNode removalSentinel) {
     transformAnnotations(node.annotations, node);
     return node;
   }
@@ -497,8 +498,8 @@
   // Handle definition of constants:
 
   @override
-  FunctionNode visitFunctionNode(FunctionNode node) {
-    transformList(node.typeParameters, this, node);
+  FunctionNode visitFunctionNode(FunctionNode node, TreeNode removalSentinel) {
+    transformTypeParameterList(node.typeParameters, node);
     final int positionalParameterCount = node.positionalParameters.length;
     for (int i = 0; i < positionalParameterCount; ++i) {
       final VariableDeclaration variable = node.positionalParameters[i];
@@ -518,13 +519,14 @@
       }
     }
     if (node.body != null) {
-      node.body = node.body.accept<TreeNode>(this)..parent = node;
+      node.body = transform(node.body)..parent = node;
     }
     return node;
   }
 
   @override
-  VariableDeclaration visitVariableDeclaration(VariableDeclaration node) {
+  Statement visitVariableDeclaration(
+      VariableDeclaration node, TreeNode removalSentinel) {
     transformAnnotations(node.annotations, node);
 
     if (node.initializer != null) {
@@ -540,19 +542,18 @@
             // If the constant is unevaluated we need to keep the expression,
             // so that, in the case the constant contains error but the local
             // is unused, the error will still be reported.
-            return null;
+            return removalSentinel /*!*/ ?? node;
           }
         }
       } else {
-        node.initializer = node.initializer.accept<TreeNode>(this)
-          ..parent = node;
+        node.initializer = transform(node.initializer)..parent = node;
       }
     }
     return node;
   }
 
   @override
-  Field visitField(Field node) {
+  Field visitField(Field node, TreeNode removalSentinel) {
     StaticTypeContext oldStaticTypeContext = _staticTypeContext;
     _staticTypeContext = new StaticTypeContext(node, typeEnvironment);
     Field field = constantEvaluator.withNewEnvironment(() {
@@ -564,13 +565,12 @@
 
         // If this constant is inlined, remove it.
         if (!keepFields && shouldInline(node.initializer)) {
-          return null;
+          return removalSentinel;
         }
       } else {
         transformAnnotations(node.annotations, node);
         if (node.initializer != null) {
-          node.initializer = node.initializer.accept<TreeNode>(this)
-            ..parent = node;
+          node.initializer = transform(node.initializer)..parent = node;
         }
       }
       return node;
@@ -582,7 +582,7 @@
   // Handle use-sites of constants (and "inline" constant expressions):
 
   @override
-  Expression visitSymbolLiteral(SymbolLiteral node) {
+  Expression visitSymbolLiteral(SymbolLiteral node, TreeNode removalSentinel) {
     return makeConstantExpression(
         constantEvaluator.evaluate(_staticTypeContext, node), node);
   }
@@ -593,9 +593,9 @@
   }
 
   @override
-  Expression visitEqualsCall(EqualsCall node) {
-    Expression left = node.left.accept<TreeNode>(this);
-    Expression right = node.right.accept<TreeNode>(this);
+  Expression visitEqualsCall(EqualsCall node, TreeNode removalSentinel) {
+    Expression left = transform(node.left);
+    Expression right = transform(node.right);
     if (_isNull(left)) {
       return new EqualsNull(right, isNot: node.isNot)
         ..fileOffset = node.fileOffset;
@@ -609,7 +609,7 @@
   }
 
   @override
-  Expression visitStaticGet(StaticGet node) {
+  Expression visitStaticGet(StaticGet node, TreeNode removalSentinel) {
     final Member target = node.target;
     if (target is Field && target.isConst) {
       // Make sure the initializer is evaluated first.
@@ -625,27 +625,28 @@
     } else if (target is Procedure && target.kind == ProcedureKind.Method) {
       return evaluateAndTransformWithContext(node, node);
     }
-    return super.visitStaticGet(node);
+    return super.visitStaticGet(node, removalSentinel);
   }
 
   @override
-  Expression visitStaticTearOff(StaticTearOff node) {
+  Expression visitStaticTearOff(StaticTearOff node, TreeNode removalSentinel) {
     final Member target = node.target;
     if (target is Procedure && target.kind == ProcedureKind.Method) {
       return evaluateAndTransformWithContext(node, node);
     }
-    return super.visitStaticTearOff(node);
+    return super.visitStaticTearOff(node, removalSentinel);
   }
 
   @override
-  SwitchCase visitSwitchCase(SwitchCase node) {
+  SwitchCase visitSwitchCase(SwitchCase node, TreeNode removalSentinel) {
     transformExpressions(node.expressions, node);
-    return super.visitSwitchCase(node);
+    return super.visitSwitchCase(node, removalSentinel);
   }
 
   @override
-  SwitchStatement visitSwitchStatement(SwitchStatement node) {
-    SwitchStatement result = super.visitSwitchStatement(node);
+  SwitchStatement visitSwitchStatement(
+      SwitchStatement node, TreeNode removalSentinel) {
+    SwitchStatement result = super.visitSwitchStatement(node, removalSentinel);
     Library library = constantEvaluator.libraryOf(node);
     if (library != null && library.isNonNullableByDefault) {
       for (SwitchCase switchCase in node.cases) {
@@ -672,7 +673,7 @@
   }
 
   @override
-  Expression visitVariableGet(VariableGet node) {
+  Expression visitVariableGet(VariableGet node, TreeNode removalSentinel) {
     final VariableDeclaration variable = node.variable;
     if (variable.isConst) {
       variable.initializer =
@@ -682,74 +683,80 @@
         return evaluateAndTransformWithContext(node, node);
       }
     }
-    return super.visitVariableGet(node);
+    return super.visitVariableGet(node, removalSentinel);
   }
 
   @override
-  Expression visitListLiteral(ListLiteral node) {
+  Expression visitListLiteral(ListLiteral node, TreeNode removalSentinel) {
     if (node.isConst) {
       return evaluateAndTransformWithContext(node, node);
     }
-    return super.visitListLiteral(node);
+    return super.visitListLiteral(node, removalSentinel);
   }
 
   @override
-  Expression visitListConcatenation(ListConcatenation node) {
+  Expression visitListConcatenation(
+      ListConcatenation node, TreeNode removalSentinel) {
     return evaluateAndTransformWithContext(node, node);
   }
 
   @override
-  Expression visitSetLiteral(SetLiteral node) {
+  Expression visitSetLiteral(SetLiteral node, TreeNode removalSentinel) {
     if (node.isConst) {
       return evaluateAndTransformWithContext(node, node);
     }
-    return super.visitSetLiteral(node);
+    return super.visitSetLiteral(node, removalSentinel);
   }
 
   @override
-  Expression visitSetConcatenation(SetConcatenation node) {
+  Expression visitSetConcatenation(
+      SetConcatenation node, TreeNode removalSentinel) {
     return evaluateAndTransformWithContext(node, node);
   }
 
   @override
-  Expression visitMapLiteral(MapLiteral node) {
+  Expression visitMapLiteral(MapLiteral node, TreeNode removalSentinel) {
     if (node.isConst) {
       return evaluateAndTransformWithContext(node, node);
     }
-    return super.visitMapLiteral(node);
+    return super.visitMapLiteral(node, removalSentinel);
   }
 
   @override
-  Expression visitTypeLiteral(TypeLiteral node) {
+  Expression visitTypeLiteral(TypeLiteral node, TreeNode removalSentinel) {
     if (!containsFreeTypeVariables(node.type)) {
       return evaluateAndTransformWithContext(node, node);
     }
-    return super.visitTypeLiteral(node);
+    return super.visitTypeLiteral(node, removalSentinel);
   }
 
   @override
-  Expression visitMapConcatenation(MapConcatenation node) {
+  Expression visitMapConcatenation(
+      MapConcatenation node, TreeNode removalSentinel) {
     return evaluateAndTransformWithContext(node, node);
   }
 
   @override
-  Expression visitConstructorInvocation(ConstructorInvocation node) {
+  Expression visitConstructorInvocation(
+      ConstructorInvocation node, TreeNode removalSentinel) {
     if (node.isConst) {
       return evaluateAndTransformWithContext(node, node);
     }
-    return super.visitConstructorInvocation(node);
+    return super.visitConstructorInvocation(node, removalSentinel);
   }
 
   @override
-  Expression visitStaticInvocation(StaticInvocation node) {
+  Expression visitStaticInvocation(
+      StaticInvocation node, TreeNode removalSentinel) {
     if (node.isConst) {
       return evaluateAndTransformWithContext(node, node);
     }
-    return super.visitStaticInvocation(node);
+    return super.visitStaticInvocation(node, removalSentinel);
   }
 
   @override
-  Expression visitConstantExpression(ConstantExpression node) {
+  Expression visitConstantExpression(
+      ConstantExpression node, TreeNode removalSentinel) {
     Constant constant = node.constant;
     if (constant is UnevaluatedConstant) {
       Expression expression = constant.expression;
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 8d0c5b0..fbbd0ca 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
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 import 'package:kernel/target/targets.dart';
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index c407429..d179e00 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -7,8 +7,6 @@
 /// A library to help generate expression.
 library fasta.expression_generator;
 
-import 'dart:core' hide MapEntry;
-
 import 'package:_fe_analyzer_shared/src/parser/parser.dart'
     show lengthForToken, lengthOfSpan;
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 30344fd..9be6294 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -6,8 +6,6 @@
 
 library fasta.fangorn;
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 import 'package:kernel/src/printer.dart';
 
@@ -777,6 +775,10 @@
     throw unsupported("transformChildren", fileOffset, uri);
   }
 
+  transformOrRemoveChildren(v) {
+    throw unsupported("transformOrRemoveChildren", fileOffset, uri);
+  }
+
   @override
   String toString() {
     return "_VariablesDeclaration(${toStringInternal()})";
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
index f37b35c..b45a75c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
@@ -8,7 +8,7 @@
 
 import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/src/assumptions.dart';
 import 'package:kernel/src/legacy_erasure.dart';
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 be8f723..13d0970 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -4,12 +4,9 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:_fe_analyzer_shared/src/util/link.dart';
 import 'package:front_end/src/api_prototype/lowering_predicates.dart';
-import 'package:kernel/ast.dart'
-    hide Reference; // Work around https://github.com/dart-lang/sdk/issues/44667
+import 'package:kernel/ast.dart';
 import 'package:kernel/src/legacy_erasure.dart';
 import 'package:kernel/type_algebra.dart' show Substitution;
 import 'package:kernel/type_environment.dart';
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 89039e8..faf4716 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -20,8 +20,6 @@
 /// kernel class, because multiple constructs in Dart may desugar to a tree
 /// with the same kind of root node.
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 import 'package:kernel/text/ast_to_text.dart' show Precedence, Printer;
 import 'package:kernel/src/printer.dart';
@@ -262,23 +260,47 @@
   @override
   void transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
+      variable = v.transform(variable);
       variable?.parent = this;
     }
     if (iterable != null) {
-      iterable = iterable.accept<TreeNode>(v);
+      iterable = v.transform(iterable);
       iterable?.parent = this;
     }
     if (syntheticAssignment != null) {
-      syntheticAssignment = syntheticAssignment.accept<TreeNode>(v);
+      syntheticAssignment = v.transform(syntheticAssignment);
       syntheticAssignment?.parent = this;
     }
     if (expressionEffects != null) {
-      expressionEffects = expressionEffects.accept<TreeNode>(v);
+      expressionEffects = v.transform(expressionEffects);
       expressionEffects?.parent = this;
     }
     if (body != null) {
-      body = body.accept<TreeNode>(v);
+      body = v.transform(body);
+      body?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (variable != null) {
+      variable = v.transform(variable);
+      variable?.parent = this;
+    }
+    if (iterable != null) {
+      iterable = v.transform(iterable);
+      iterable?.parent = this;
+    }
+    if (syntheticAssignment != null) {
+      syntheticAssignment = v.transform(syntheticAssignment);
+      syntheticAssignment?.parent = this;
+    }
+    if (expressionEffects != null) {
+      expressionEffects = v.transform(expressionEffects);
+      expressionEffects?.parent = this;
+    }
+    if (body != null) {
+      body = v.transform(body);
       body?.parent = this;
     }
   }
@@ -320,12 +342,25 @@
   @override
   void transformChildren(Transformer v) {
     if (tryBlock != null) {
-      tryBlock = tryBlock.accept<TreeNode>(v);
+      tryBlock = v.transform(tryBlock);
       tryBlock?.parent = this;
     }
-    transformList(catchBlocks, v, this);
+    v.transformList(catchBlocks, this);
     if (finallyBlock != null) {
-      finallyBlock = finallyBlock.accept<TreeNode>(v);
+      finallyBlock = v.transform(finallyBlock);
+      finallyBlock?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (tryBlock != null) {
+      tryBlock = v.transformOrRemoveStatement(tryBlock);
+      tryBlock?.parent = this;
+    }
+    v.transformCatchList(catchBlocks, this);
+    if (finallyBlock != null) {
+      finallyBlock = v.transformOrRemoveStatement(finallyBlock);
       finallyBlock?.parent = this;
     }
   }
@@ -586,10 +621,19 @@
   @override
   void transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
+      variable = v.transform(variable);
       variable?.parent = this;
     }
-    transformList(expressions, v, this);
+    v.transformList(expressions, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (variable != null) {
+      variable = v.transformOrRemoveVariableDeclaration(variable);
+      variable?.parent = this;
+    }
+    v.transformExpressionList(expressions, this);
   }
 
   @override
@@ -646,11 +690,23 @@
   @override
   void transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
+      variable = v.transform(variable);
       variable?.parent = this;
     }
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
+      expression = v.transform(expression);
+      expression?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (variable != null) {
+      variable = v.transformOrRemoveVariableDeclaration(variable);
+      variable?.parent = this;
+    }
+    if (expression != null) {
+      expression = v.transformOrRemoveExpression(expression);
       expression?.parent = this;
     }
   }
@@ -849,11 +905,23 @@
   @override
   void transformChildren(Transformer v) {
     if (left != null) {
-      left = left.accept<TreeNode>(v);
+      left = v.transform(left);
       left?.parent = this;
     }
     if (right != null) {
-      right = right.accept<TreeNode>(v);
+      right = v.transform(right);
+      right?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (left != null) {
+      left = v.transformOrRemoveExpression(left);
+      left?.parent = this;
+    }
+    if (right != null) {
+      right = v.transformOrRemoveExpression(right);
       right?.parent = this;
     }
   }
@@ -1040,11 +1108,23 @@
   @override
   void transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
+      expression = v.transform(expression);
       expression?.parent = this;
     }
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
+      arguments = v.transform(arguments);
+      arguments?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (expression != null) {
+      expression = v.transformOrRemoveExpression(expression);
+      expression?.parent = this;
+    }
+    if (arguments != null) {
+      arguments = v.transformOrRemove(arguments, dummyArguments);
       arguments?.parent = this;
     }
   }
@@ -1122,13 +1202,25 @@
   }
 
   @override
-  transformChildren(Transformer v) {
+  void transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
+      variable = v.transform(variable);
       variable?.parent = this;
     }
     if (invocation != null) {
-      invocation = invocation.accept<TreeNode>(v);
+      invocation = v.transform(invocation);
+      invocation?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (variable != null) {
+      variable = v.transformOrRemoveVariableDeclaration(variable);
+      variable?.parent = this;
+    }
+    if (invocation != null) {
+      invocation = v.transformOrRemoveExpression(invocation);
       invocation?.parent = this;
     }
   }
@@ -1195,13 +1287,25 @@
   }
 
   @override
-  transformChildren(Transformer v) {
+  void transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
+      variable = v.transform(variable);
       variable?.parent = this;
     }
     if (read != null) {
-      read = read.accept<TreeNode>(v);
+      read = v.transform(read);
+      read?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (variable != null) {
+      variable = v.transform(variable);
+      variable?.parent = this;
+    }
+    if (read != null) {
+      read = v.transform(read);
       read?.parent = this;
     }
   }
@@ -1267,13 +1371,25 @@
   }
 
   @override
-  transformChildren(Transformer v) {
+  void transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
+      variable = v.transform(variable);
       variable?.parent = this;
     }
     if (write != null) {
-      write = write.accept<TreeNode>(v);
+      write = v.transform(write);
+      write?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (variable != null) {
+      variable = v.transformOrRemoveVariableDeclaration(variable);
+      variable?.parent = this;
+    }
+    if (write != null) {
+      write = v.transformOrRemoveExpression(write);
       write?.parent = this;
     }
   }
@@ -1510,6 +1626,11 @@
         isLate: isLate || lateGetter != null, type: lateType ?? type);
     printer.write(';');
   }
+
+  @override
+  String toString() {
+    return "VariableDeclarationImpl(${toStringInternal()})";
+  }
 }
 
 /// Front end specific implementation of [VariableGet].
@@ -1570,19 +1691,14 @@
 
   @override
   void visitChildren(Visitor<dynamic> v) {
-    import?.accept(v);
-    target?.accept(v);
+    v.visitProcedureReference(target);
   }
 
   @override
-  void transformChildren(Transformer v) {
-    if (import != null) {
-      import = import.accept<TreeNode>(v);
-    }
-    if (target != null) {
-      target = target.accept<TreeNode>(v);
-    }
-  }
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -1651,11 +1767,23 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (rhs != null) {
-      rhs = rhs.accept<TreeNode>(v);
+      rhs = v.transform(rhs);
+      rhs?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (rhs != null) {
+      rhs = v.transformOrRemoveExpression(rhs);
       rhs?.parent = this;
     }
   }
@@ -1720,11 +1848,23 @@
   @override
   void transformChildren(Transformer v) {
     if (read != null) {
-      read = read.accept<TreeNode>(v);
+      read = v.transform(read);
       read?.parent = this;
     }
     if (write != null) {
-      write = write.accept<TreeNode>(v);
+      write = v.transform(write);
+      write?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (read != null) {
+      read = v.transformOrRemoveExpression(read);
+      read?.parent = this;
+    }
+    if (write != null) {
+      write = v.transformOrRemoveExpression(write);
       write?.parent = this;
     }
   }
@@ -1843,11 +1983,23 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (rhs != null) {
-      rhs = rhs.accept<TreeNode>(v);
+      rhs = v.transform(rhs);
+      rhs?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (rhs != null) {
+      rhs = v.transformOrRemoveExpression(rhs);
       rhs?.parent = this;
     }
   }
@@ -1923,11 +2075,23 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (rhs != null) {
-      rhs = rhs.accept<TreeNode>(v);
+      rhs = v.transform(rhs);
+      rhs?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (rhs != null) {
+      rhs = v.transformOrRemoveExpression(rhs);
       rhs?.parent = this;
     }
   }
@@ -1999,11 +2163,23 @@
   @override
   void transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
+      variable = v.transform(variable);
       variable?.parent = this;
     }
     if (write != null) {
-      write = write.accept<TreeNode>(v);
+      write = v.transform(write);
+      write?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (variable != null) {
+      variable = v.transformOrRemoveVariableDeclaration(variable);
+      variable?.parent = this;
+    }
+    if (write != null) {
+      write = v.transformOrRemoveVariableDeclaration(write);
       write?.parent = this;
     }
   }
@@ -2052,11 +2228,23 @@
   @override
   void transformChildren(Transformer v) {
     if (read != null) {
-      read = read.accept<TreeNode>(v);
+      read = v.transform(read);
       read?.parent = this;
     }
     if (write != null) {
-      write = write.accept<TreeNode>(v);
+      write = v.transform(write);
+      write?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (read != null) {
+      read = v.transformOrRemoveVariableDeclaration(read);
+      read?.parent = this;
+    }
+    if (write != null) {
+      write = v.transformOrRemoveVariableDeclaration(write);
       write?.parent = this;
     }
   }
@@ -2105,11 +2293,23 @@
   @override
   void transformChildren(Transformer v) {
     if (read != null) {
-      read = read.accept<TreeNode>(v);
+      read = v.transform(read);
       read?.parent = this;
     }
     if (write != null) {
-      write = write.accept<TreeNode>(v);
+      write = v.transform(write);
+      write?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (read != null) {
+      read = v.transform(read);
+      read?.parent = this;
+    }
+    if (write != null) {
+      write = v.transform(write);
       write?.parent = this;
     }
   }
@@ -2158,11 +2358,23 @@
   @override
   void transformChildren(Transformer v) {
     if (read != null) {
-      read = read.accept<TreeNode>(v);
+      read = v.transform(read);
       read?.parent = this;
     }
     if (write != null) {
-      write = write.accept<TreeNode>(v);
+      write = v.transform(write);
+      write?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (read != null) {
+      read = v.transformOrRemoveVariableDeclaration(read);
+      read?.parent = this;
+    }
+    if (write != null) {
+      write = v.transformOrRemoveVariableDeclaration(write);
       write?.parent = this;
     }
   }
@@ -2204,11 +2416,23 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (index != null) {
-      index = index.accept<TreeNode>(v);
+      index = v.transform(index);
+      index?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (index != null) {
+      index = v.transformOrRemoveExpression(index);
       index?.parent = this;
     }
   }
@@ -2270,15 +2494,31 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (index != null) {
-      index = index.accept<TreeNode>(v);
+      index = v.transform(index);
       index?.parent = this;
     }
     if (value != null) {
-      value = value.accept<TreeNode>(v);
+      value = v.transform(value);
+      value?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (index != null) {
+      index = v.transformOrRemoveExpression(index);
+      index?.parent = this;
+    }
+    if (value != null) {
+      value = v.transformOrRemoveExpression(value);
       value?.parent = this;
     }
   }
@@ -2335,11 +2575,23 @@
   @override
   void transformChildren(Transformer v) {
     if (index != null) {
-      index = index.accept<TreeNode>(v);
+      index = v.transform(index);
       index?.parent = this;
     }
     if (value != null) {
-      value = value.accept<TreeNode>(v);
+      value = v.transform(value);
+      value?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (index != null) {
+      index = v.transformOrRemoveExpression(index);
+      index?.parent = this;
+    }
+    if (value != null) {
+      value = v.transformOrRemoveExpression(value);
       value?.parent = this;
     }
   }
@@ -2416,15 +2668,31 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (index != null) {
-      index = index.accept<TreeNode>(v);
+      index = v.transform(index);
       index?.parent = this;
     }
     if (value != null) {
-      value = value.accept<TreeNode>(v);
+      value = v.transform(value);
+      value?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (index != null) {
+      index = v.transformOrRemoveExpression(index);
+      index?.parent = this;
+    }
+    if (value != null) {
+      value = v.transformOrRemoveExpression(value);
       value?.parent = this;
     }
   }
@@ -2524,15 +2792,31 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (index != null) {
-      index = index.accept<TreeNode>(v);
+      index = v.transform(index);
       index?.parent = this;
     }
     if (value != null) {
-      value = value.accept<TreeNode>(v);
+      value = v.transform(value);
+      value?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (index != null) {
+      index = v.transformOrRemoveExpression(index);
+      index?.parent = this;
+    }
+    if (value != null) {
+      value = v.transformOrRemoveExpression(value);
       value?.parent = this;
     }
   }
@@ -2615,11 +2899,23 @@
   @override
   void transformChildren(Transformer v) {
     if (index != null) {
-      index = index.accept<TreeNode>(v);
+      index = v.transform(index);
       index?.parent = this;
     }
     if (value != null) {
-      value = value.accept<TreeNode>(v);
+      value = v.transform(value);
+      value?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (index != null) {
+      index = v.transformOrRemoveExpression(index);
+      index?.parent = this;
+    }
+    if (value != null) {
+      value = v.transformOrRemoveExpression(value);
       value?.parent = this;
     }
   }
@@ -2715,15 +3011,31 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (index != null) {
-      index = index.accept<TreeNode>(v);
+      index = v.transform(index);
       index?.parent = this;
     }
     if (value != null) {
-      value = value.accept<TreeNode>(v);
+      value = v.transform(value);
+      value?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (index != null) {
+      index = v.transformOrRemoveExpression(index);
+      index?.parent = this;
+    }
+    if (value != null) {
+      value = v.transformOrRemoveExpression(value);
       value?.parent = this;
     }
   }
@@ -2808,15 +3120,31 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (index != null) {
-      index = index.accept<TreeNode>(v);
+      index = v.transform(index);
       index?.parent = this;
     }
     if (rhs != null) {
-      rhs = rhs.accept<TreeNode>(v);
+      rhs = v.transform(rhs);
+      rhs?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (index != null) {
+      index = v.transformOrRemoveExpression(index);
+      index?.parent = this;
+    }
+    if (rhs != null) {
+      rhs = v.transformOrRemoveExpression(rhs);
       rhs?.parent = this;
     }
   }
@@ -2947,11 +3275,23 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (rhs != null) {
-      rhs = rhs.accept<TreeNode>(v);
+      rhs = v.transform(rhs);
+      rhs?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (rhs != null) {
+      rhs = v.transformOrRemoveExpression(rhs);
       rhs?.parent = this;
     }
   }
@@ -3056,11 +3396,23 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (value != null) {
-      value = value.accept<TreeNode>(v);
+      value = v.transform(value);
+      value?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (value != null) {
+      value = v.transformOrRemoveExpression(value);
       value?.parent = this;
     }
   }
@@ -3156,11 +3508,23 @@
   @override
   void transformChildren(Transformer v) {
     if (index != null) {
-      index = index.accept<TreeNode>(v);
+      index = v.transform(index);
       index?.parent = this;
     }
     if (rhs != null) {
-      rhs = rhs.accept<TreeNode>(v);
+      rhs = v.transform(rhs);
+      rhs?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (index != null) {
+      index = v.transformOrRemoveExpression(index);
+      index?.parent = this;
+    }
+    if (rhs != null) {
+      rhs = v.transformOrRemoveExpression(rhs);
       rhs?.parent = this;
     }
   }
@@ -3274,15 +3638,31 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (index != null) {
-      index = index.accept<TreeNode>(v);
+      index = v.transform(index);
       index?.parent = this;
     }
     if (rhs != null) {
-      rhs = rhs.accept<TreeNode>(v);
+      rhs = v.transform(rhs);
+      rhs?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transformOrRemoveExpression(receiver);
+      receiver?.parent = this;
+    }
+    if (index != null) {
+      index = v.transformOrRemoveExpression(index);
+      index?.parent = this;
+    }
+    if (rhs != null) {
+      rhs = v.transformOrRemoveExpression(rhs);
       rhs?.parent = this;
     }
   }
@@ -3360,11 +3740,23 @@
   @override
   void transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
+      receiver = v.transform(receiver);
       receiver?.parent = this;
     }
     if (value != null) {
-      value = value.accept<TreeNode>(v);
+      value = v.transform(value);
+      value?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver?.parent = this;
+    }
+    if (value != null) {
+      value = v.transform(value);
       value?.parent = this;
     }
   }
@@ -3411,11 +3803,23 @@
   @override
   void transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
+      variable = v.transform(variable);
       variable?.parent = this;
     }
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
+      expression = v.transform(expression);
+      expression?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (variable != null) {
+      variable = v.transformOrRemoveVariableDeclaration(variable);
+      variable?.parent = this;
+    }
+    if (expression != null) {
+      expression = v.transformOrRemoveExpression(expression);
       expression?.parent = this;
     }
   }
@@ -3486,7 +3890,15 @@
   @override
   void transformChildren(Transformer v) {
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
+      arguments = v.transform(arguments);
+      arguments?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (arguments != null) {
+      arguments = v.transformOrRemove(arguments, dummyArguments);
       arguments?.parent = this;
     }
   }
@@ -3527,11 +3939,23 @@
   @override
   void transformChildren(Transformer v) {
     if (left != null) {
-      left = left.accept<TreeNode>(v);
+      left = v.transform(left);
       left?.parent = this;
     }
     if (right != null) {
-      right = right.accept<TreeNode>(v);
+      right = v.transform(right);
+      right?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (left != null) {
+      left = v.transformOrRemoveExpression(left);
+      left?.parent = this;
+    }
+    if (right != null) {
+      right = v.transformOrRemoveExpression(right);
       right?.parent = this;
     }
   }
@@ -3582,11 +4006,23 @@
   @override
   void transformChildren(Transformer v) {
     if (left != null) {
-      left = left.accept<TreeNode>(v);
+      left = v.transform(left);
       left?.parent = this;
     }
     if (right != null) {
-      right = right.accept<TreeNode>(v);
+      right = v.transform(right);
+      right?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (left != null) {
+      left = v.transformOrRemoveExpression(left);
+      left?.parent = this;
+    }
+    if (right != null) {
+      right = v.transformOrRemoveExpression(right);
       right?.parent = this;
     }
   }
@@ -3633,7 +4069,15 @@
   @override
   void transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
+      expression = v.transform(expression);
+      expression?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (expression != null) {
+      expression = v.transformOrRemoveExpression(expression);
       expression?.parent = this;
     }
   }
@@ -3682,7 +4126,15 @@
   @override
   void transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
+      expression = v.transform(expression);
+      expression?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (expression != null) {
+      expression = v.transformOrRemoveExpression(expression);
       expression?.parent = this;
     }
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart b/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart
index c361101..93b6350 100644
--- a/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.9
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/visitor.dart';
 
 import '../type_inference/type_schema.dart';
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 577359b..1f87bde 100644
--- a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.9
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/core_types.dart';
 
 import '../../base/nnbd_mode.dart';
diff --git a/pkg/front_end/lib/src/fasta/kernel/member_covariance.dart b/pkg/front_end/lib/src/fasta/kernel/member_covariance.dart
index 6d4a9f1..c4901b9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/member_covariance.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/member_covariance.dart
@@ -6,7 +6,7 @@
 
 import 'dart:math';
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 
 /// Class that holds the covariant and generic-covariant-impl information for
 /// a member.
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 220157e..0866c33 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
@@ -6,8 +6,6 @@
 
 library fasta.transform_collections;
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 
 import 'package:kernel/core_types.dart' show CoreTypes;
@@ -281,8 +279,8 @@
         element.condition?.accept<TreeNode>(this),
         element.updates,
         loopBody);
-    transformList(loop.variables, this, loop);
-    transformList(loop.updates, this, loop);
+    transformList(loop.variables, loop);
+    transformList(loop.updates, loop);
     _dataForTesting?.registerAlias(element, loop);
     body.add(loop);
   }
@@ -533,8 +531,8 @@
     ForStatement loop = _createForStatement(entry.fileOffset, entry.variables,
         entry.condition?.accept<TreeNode>(this), entry.updates, loopBody);
     _dataForTesting?.registerAlias(entry, loop);
-    transformList(loop.variables, this, loop);
-    transformList(loop.updates, this, loop);
+    transformList(loop.variables, loop);
+    transformList(loop.updates, loop);
     body.add(loop);
   }
 
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 250493f..7195f01 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,8 +6,6 @@
 
 library fasta.transform_set_literals;
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 
 import 'package:kernel/core_types.dart' show CoreTypes;
diff --git a/pkg/front_end/lib/src/fasta/kernel/verifier.dart b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
index ddfef29..468697e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/verifier.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
@@ -6,8 +6,6 @@
 
 library fasta.verifier;
 
-import 'dart:core' hide MapEntry;
-
 import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
 
 import 'package:kernel/ast.dart';
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index 4f8e52b..004901a 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -6,7 +6,7 @@
 
 library fasta.scope;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/core_types.dart';
 
 import 'builder/builder.dart';
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 6d6dca8..92ac343 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
@@ -7,7 +7,7 @@
 library fasta.source_class_builder;
 
 import 'package:front_end/src/fasta/kernel/combined_member_signature.dart';
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 import 'package:kernel/reference_from_index.dart' show IndexedClass;
 import 'package:kernel/src/bounds_checks.dart';
diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
index 1538023..a1f535a 100644
--- a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 import 'package:kernel/type_environment.dart';
 
diff --git a/pkg/front_end/lib/src/fasta/type_inference/factor_type.dart b/pkg/front_end/lib/src/fasta/type_inference/factor_type.dart
index a72c547..7e90983 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/factor_type.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/factor_type.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.9
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/type_environment.dart';
 
 /// Computes the "remainder" of [T] when [S] has been removed from consideration
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
index 4039519..24f2850 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 
 import 'package:kernel/core_types.dart' show CoreTypes;
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
index 705469d..569d058 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.9
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/core_types.dart';
 
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
index c75bd34..f391d17 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.9
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/src/replacement_visitor.dart';
 
 /// Returns `true` if type contains a promoted type variable.
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 58ad7fc..a61e28f 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
@@ -7,8 +7,7 @@
 import 'dart:core' hide MapEntry;
 import 'dart:core' as core;
 
-import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart'
-    hide Reference; // Work around https://github.com/dart-lang/sdk/issues/44667
+import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
 
 import 'package:_fe_analyzer_shared/src/testing/id.dart';
 import 'package:_fe_analyzer_shared/src/util/link.dart';
@@ -17,8 +16,7 @@
 import 'package:front_end/src/fasta/type_inference/type_demotion.dart';
 import 'package:front_end/src/testing/id_extractor.dart';
 
-import 'package:kernel/ast.dart'
-    hide Reference; // Work around https://github.com/dart-lang/sdk/issues/44667
+import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 import 'package:kernel/core_types.dart' show CoreTypes;
 import 'package:kernel/type_algebra.dart';
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
index f6598b6..9e7c2ea 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.9
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/src/replacement_visitor.dart';
 
 import 'type_schema.dart' show UnknownType;
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
index 5e32e19..7b37c14 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.9
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 3858ee0..30beca7e 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -375,6 +375,7 @@
 enforce
 enforced
 enforces
+enforcing
 enumerates
 env
 eof
diff --git a/pkg/front_end/test/text_representation/empty_reference_test.dart b/pkg/front_end/test/text_representation/empty_reference_test.dart
index 22643b3..a33bd6b 100644
--- a/pkg/front_end/test/text_representation/empty_reference_test.dart
+++ b/pkg/front_end/test/text_representation/empty_reference_test.dart
@@ -85,7 +85,7 @@
 void testMembers() {
   testExpression(new PropertyGet(new IntLiteral(0), new Name('foo')), '''
 0.foo''');
-  testExpression(new StaticGet(null), '''
+  testExpression(new StaticGet.byReference(null), '''
 <missing-member-reference>''');
 
   Reference unlinkedMemberName = new Reference();
diff --git a/pkg/front_end/tool/_fasta/bench_maker.dart b/pkg/front_end/tool/_fasta/bench_maker.dart
index dbfbb79..32e478f 100644
--- a/pkg/front_end/tool/_fasta/bench_maker.dart
+++ b/pkg/front_end/tool/_fasta/bench_maker.dart
@@ -10,7 +10,7 @@
 
 import "dart:io" show File;
 
-import "package:kernel/ast.dart" hide MapEntry;
+import "package:kernel/ast.dart";
 
 import "package:front_end/src/fasta/type_inference/type_schema.dart"
     show UnknownType;
diff --git a/pkg/front_end/tool/_fasta/generate_experimental_flags.dart b/pkg/front_end/tool/_fasta/generate_experimental_flags.dart
index 5911b3a..c3ec736 100644
--- a/pkg/front_end/tool/_fasta/generate_experimental_flags.dart
+++ b/pkg/front_end/tool/_fasta/generate_experimental_flags.dart
@@ -63,8 +63,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.
 
-// @dart = 2.9
-
 // NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
 //
 // Instead modify 'tools/experimental_features.yaml' and run
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index fa63366..fd0b0bc 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.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.
 
-// @dart = 2.9
-
 /// -----------------------------------------------------------------------
 ///                          WHEN CHANGING THIS FILE:
 /// -----------------------------------------------------------------------
@@ -142,7 +140,7 @@
   final int hashCode = _hashCounter = (_hashCounter + 1) & 0x3fffffff;
   static const int noOffset = -1;
 
-  TreeNode parent;
+  TreeNode? parent;
 
   /// Offset in the source file it comes from.
   ///
@@ -151,8 +149,10 @@
   int fileOffset = noOffset;
 
   R accept<R>(TreeVisitor<R> v);
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg);
   void visitChildren(Visitor v);
   void transformChildren(Transformer v);
+  void transformOrRemoveChildren(RemovingTransformer v);
 
   /// Replaces [child] with [replacement].
   ///
@@ -164,6 +164,7 @@
   ///
   /// [replacement] must be non-null.
   void replaceChild(TreeNode child, TreeNode replacement) {
+    // ignore: unnecessary_null_comparison
     assert(replacement != null);
     transformChildren(new _ChildReplacer(child, replacement));
   }
@@ -176,24 +177,26 @@
   ///
   /// [replacement] must be non-null.
   void replaceWith(TreeNode replacement) {
+    // ignore: unnecessary_null_comparison
     assert(replacement != null);
-    parent.replaceChild(this, replacement);
+    parent!.replaceChild(this, replacement);
     parent = null;
   }
 
-  Component get enclosingComponent => parent?.enclosingComponent;
+  // TODO(johnniwinther): Make this non-nullable.
+  Component? get enclosingComponent => parent?.enclosingComponent;
 
   /// Returns the best known source location of the given AST node, or `null` if
   /// the node is orphaned.
   ///
   /// This getter is intended for diagnostics and debugging, and should be
   /// avoided in production code.
-  Location get location {
+  Location? get location {
     if (fileOffset == noOffset) return parent?.location;
     return _getLocationInEnclosingFile(fileOffset);
   }
 
-  Location _getLocationInEnclosingFile(int offset) {
+  Location? _getLocationInEnclosingFile(int offset) {
     return parent?._getLocationInEnclosingFile(offset);
   }
 }
@@ -205,17 +208,16 @@
 abstract class NamedNode extends TreeNode {
   final Reference reference;
 
-  NamedNode(Reference reference)
+  NamedNode(Reference? reference)
       : this.reference = reference ?? new Reference() {
     if (this is Field) {
-      Field me = this;
-      me.getterReference.node = this;
+      (this as Field).getterReference.node = this;
     } else {
       this.reference.node = this;
     }
   }
 
-  CanonicalName get canonicalName => reference?.canonicalName;
+  CanonicalName? get canonicalName => reference.canonicalName;
 
   /// This is an advanced feature.
   ///
@@ -229,7 +231,8 @@
 
 abstract class FileUriNode extends TreeNode {
   /// The URI of the source file this node was loaded from.
-  Uri get fileUri;
+  // TODO(johnniwinther): Make this non-nullable.
+  Uri? get fileUri;
 }
 
 abstract class Annotatable extends TreeNode {
@@ -241,17 +244,17 @@
 ///
 /// There is only one reference object per [NamedNode].
 class Reference {
-  CanonicalName canonicalName;
+  CanonicalName? canonicalName;
 
-  NamedNode _node;
+  NamedNode? _node;
 
-  NamedNode get node {
+  NamedNode? get node {
     if (_node == null) {
       // Either this is an unbound reference or it belongs to a lazy-loaded
       // (and not yet loaded) class. If it belongs to a lazy-loaded class,
       // load the class.
 
-      CanonicalName canonicalNameParent = canonicalName?.parent;
+      CanonicalName? canonicalNameParent = canonicalName?.parent;
       while (canonicalNameParent != null) {
         if (canonicalNameParent.name.startsWith("@")) {
           break;
@@ -259,8 +262,8 @@
         canonicalNameParent = canonicalNameParent.parent;
       }
       if (canonicalNameParent != null) {
-        NamedNode parentNamedNode =
-            canonicalNameParent?.parent?.reference?._node;
+        NamedNode? parentNamedNode =
+            canonicalNameParent.parent?.reference?._node;
         if (parentNamedNode is Class) {
           Class parentClass = parentNamedNode;
           if (parentClass.lazyBuilder != null) {
@@ -272,7 +275,7 @@
     return _node;
   }
 
-  void set node(NamedNode node) {
+  void set node(NamedNode? node) {
     _node = node;
   }
 
@@ -282,10 +285,10 @@
 
   String toStringInternal() {
     if (canonicalName != null) {
-      return '${canonicalName.toStringInternal()}';
+      return '${canonicalName!.toStringInternal()}';
     }
     if (node != null) {
-      return node.toStringInternal();
+      return node!.toStringInternal();
     }
     return 'Unbound reference';
   }
@@ -356,12 +359,14 @@
   Uri importUri;
 
   /// The URI of the source file this library was loaded from.
-  Uri fileUri;
+  @override
+  Uri? fileUri;
 
-  Version _languageVersion;
+  Version? _languageVersion;
   Version get languageVersion => _languageVersion ?? defaultLanguageVersion;
 
   void setLanguageVersion(Version languageVersion) {
+    // ignore: unnecessary_null_comparison
     if (languageVersion == null) {
       throw new StateError("Trying to set language version 'null'");
     }
@@ -421,14 +426,15 @@
     }
   }
 
-  String name;
+  String? name;
 
   /// Problems in this [Library] encoded as json objects.
   ///
   /// Note that this field can be null, and by convention should be null if the
   /// list is empty.
-  List<String> problemsAsJson;
+  List<String>? problemsAsJson;
 
+  @override
   final List<Expression> annotations;
 
   final List<LibraryDependency> dependencies;
@@ -449,16 +455,16 @@
 
   Library(this.importUri,
       {this.name,
-      List<Expression> annotations,
-      List<LibraryDependency> dependencies,
-      List<LibraryPart> parts,
-      List<Typedef> typedefs,
-      List<Class> classes,
-      List<Extension> extensions,
-      List<Procedure> procedures,
-      List<Field> fields,
+      List<Expression>? annotations,
+      List<LibraryDependency>? dependencies,
+      List<LibraryPart>? parts,
+      List<Typedef>? typedefs,
+      List<Class>? classes,
+      List<Extension>? extensions,
+      List<Procedure>? procedures,
+      List<Field>? fields,
       this.fileUri,
-      Reference reference})
+      Reference? reference})
       : this.annotations = annotations ?? <Expression>[],
         this.dependencies = dependencies ?? <LibraryDependency>[],
         this.parts = parts ?? <LibraryPart>[],
@@ -501,6 +507,7 @@
   Iterable<Member> get members =>
       <Iterable<Member>>[fields, procedures].expand((x) => x);
 
+  @override
   void addAnnotation(Expression node) {
     node.parent = this;
     annotations.add(node);
@@ -532,7 +539,7 @@
   }
 
   void computeCanonicalNames() {
-    assert(canonicalName != null);
+    CanonicalName canonicalName = this.canonicalName!;
     for (int i = 0; i < typedefs.length; ++i) {
       Typedef typedef_ = typedefs[i];
       canonicalName.getChildFromTypedef(typedef_).bindTo(typedef_.reference);
@@ -543,7 +550,7 @@
       if (field.hasSetter) {
         canonicalName
             .getChildFromFieldSetter(field)
-            .bindTo(field.setterReference);
+            .bindTo(field.setterReference!);
       }
     }
     for (int i = 0; i < procedures.length; ++i) {
@@ -552,12 +559,12 @@
     }
     for (int i = 0; i < classes.length; ++i) {
       Class class_ = classes[i];
-      canonicalName.getChild(class_.name).bindTo(class_.reference);
+      canonicalName.getChild(class_.name!).bindTo(class_.reference);
       class_.computeCanonicalNames();
     }
     for (int i = 0; i < extensions.length; ++i) {
       Extension extension = extensions[i];
-      canonicalName.getChild(extension.name).bindTo(extension.reference);
+      canonicalName.getChild(extension.name!).bindTo(extension.reference);
     }
   }
 
@@ -600,9 +607,14 @@
     parts.add(node..parent = this);
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitLibrary(this);
 
-  visitChildren(Visitor v) {
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitLibrary(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
     visitList(dependencies, v);
     visitList(parts, v);
@@ -613,20 +625,34 @@
     visitList(fields, v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(annotations, v, this);
-    transformList(dependencies, v, this);
-    transformList(parts, v, this);
-    transformList(typedefs, v, this);
-    transformList(classes, v, this);
-    transformList(extensions, v, this);
-    transformList(procedures, v, this);
-    transformList(fields, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(annotations, this);
+    v.transformList(dependencies, this);
+    v.transformList(parts, this);
+    v.transformList(typedefs, this);
+    v.transformList(classes, this);
+    v.transformList(extensions, this);
+    v.transformList(procedures, this);
+    v.transformList(fields, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(annotations, this);
+    v.transformLibraryDependencyList(dependencies, this);
+    v.transformLibraryPartList(parts, this);
+    v.transformTypedefList(typedefs, this);
+    v.transformClassList(classes, this);
+    v.transformExtensionList(extensions, this);
+    v.transformProcedureList(procedures, this);
+    v.transformFieldList(fields, this);
   }
 
   static int _libraryIdCounter = 0;
   int _libraryId = ++_libraryIdCounter;
 
+  @override
   int compareTo(Library other) => _libraryId - other._libraryId;
 
   /// Returns a possibly synthesized name for this library, consistent with
@@ -639,7 +665,7 @@
     printer.write(libraryNameToString(this));
   }
 
-  Location _getLocationInEnclosingFile(int offset) {
+  Location? _getLocationInEnclosingFile(int offset) {
     return _getLocationInComponent(enclosingComponent, fileUri, offset);
   }
 
@@ -667,7 +693,7 @@
   /// with a prefix.
   ///
   /// Must be non-null for deferred imports, and must be null for exports.
-  String name;
+  String? name;
 
   final List<Combinator> combinators;
 
@@ -677,17 +703,19 @@
             flags, annotations, importedLibrary.reference, name, combinators);
 
   LibraryDependency.deferredImport(Library importedLibrary, String name,
-      {List<Combinator> combinators, List<Expression> annotations})
+      {List<Combinator>? combinators, List<Expression>? annotations})
       : this.byReference(DeferredFlag, annotations ?? <Expression>[],
             importedLibrary.reference, name, combinators ?? <Combinator>[]);
 
   LibraryDependency.import(Library importedLibrary,
-      {String name, List<Combinator> combinators, List<Expression> annotations})
+      {String? name,
+      List<Combinator>? combinators,
+      List<Expression>? annotations})
       : this.byReference(0, annotations ?? <Expression>[],
             importedLibrary.reference, name, combinators ?? <Combinator>[]);
 
   LibraryDependency.export(Library importedLibrary,
-      {List<Combinator> combinators, List<Expression> annotations})
+      {List<Combinator>? combinators, List<Expression>? annotations})
       : this.byReference(ExportFlag, annotations ?? <Expression>[],
             importedLibrary.reference, null, combinators ?? <Combinator>[]);
 
@@ -697,7 +725,7 @@
     setParents(combinators, this);
   }
 
-  Library get enclosingLibrary => parent;
+  Library get enclosingLibrary => parent as Library;
   Library get targetLibrary => importedLibraryReference.asLibrary;
 
   static const int ExportFlag = 1 << 0;
@@ -711,16 +739,29 @@
     annotations.add(annotation..parent = this);
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitLibraryDependency(this);
 
-  visitChildren(Visitor v) {
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
+      v.visitLibraryDependency(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
     visitList(combinators, v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(annotations, v, this);
-    transformList(combinators, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(annotations, this);
+    v.transformList(combinators, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(annotations, this);
+    v.transformCombinatorList(combinators, this);
   }
 
   @override
@@ -751,14 +792,25 @@
     annotations.add(annotation..parent = this);
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitLibraryPart(this);
 
-  visitChildren(Visitor v) {
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitLibraryPart(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(annotations, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(annotations, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(annotations, this);
   }
 
   @override
@@ -778,7 +830,7 @@
 
   final List<String> names;
 
-  LibraryDependency get dependency => parent;
+  LibraryDependency get dependency => parent as LibraryDependency;
 
   Combinator(this.isShow, this.names);
   Combinator.show(this.names) : isShow = true;
@@ -790,10 +842,16 @@
   R accept<R>(TreeVisitor<R> v) => v.visitCombinator(this);
 
   @override
-  visitChildren(Visitor v) {}
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitCombinator(this, arg);
 
   @override
-  transformChildren(Transformer v) {}
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -809,11 +867,13 @@
 /// Declaration of a type alias.
 class Typedef extends NamedNode implements FileUriNode {
   /// The URI of the source file that contains the declaration of this typedef.
-  Uri fileUri;
+  @override
+  Uri? fileUri;
+
   List<Expression> annotations = const <Expression>[];
   String name;
   final List<TypeParameter> typeParameters;
-  DartType type;
+  DartType? type;
 
   // The following two fields describe parameters of the underlying type when
   // that is a function type.  They are needed to keep such attributes as names
@@ -824,12 +884,12 @@
   final List<VariableDeclaration> namedParameters;
 
   Typedef(this.name, this.type,
-      {Reference reference,
+      {Reference? reference,
       this.fileUri,
-      List<TypeParameter> typeParameters,
-      List<TypeParameter> typeParametersOfFunctionType,
-      List<VariableDeclaration> positionalParameters,
-      List<VariableDeclaration> namedParameters})
+      List<TypeParameter>? typeParameters,
+      List<TypeParameter>? typeParametersOfFunctionType,
+      List<VariableDeclaration>? positionalParameters,
+      List<VariableDeclaration>? namedParameters})
       : this.typeParameters = typeParameters ?? <TypeParameter>[],
         this.typeParametersOfFunctionType =
             typeParametersOfFunctionType ?? <TypeParameter>[],
@@ -840,26 +900,44 @@
     setParents(this.typeParameters, this);
   }
 
-  Library get enclosingLibrary => parent;
+  Library get enclosingLibrary => parent as Library;
 
-  R accept<R>(TreeVisitor<R> v) {
-    return v.visitTypedef(this);
-  }
+  @override
+  R accept<R>(TreeVisitor<R> v) => v.visitTypedef(this);
 
-  transformChildren(Transformer v) {
-    transformList(annotations, v, this);
-    transformList(typeParameters, v, this);
-    if (type != null) {
-      type = v.visitDartType(type);
-    }
-  }
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitTypedef(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
     visitList(typeParameters, v);
     type?.accept(v);
   }
 
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(annotations, this);
+    v.transformList(typeParameters, this);
+    if (type != null) {
+      type = v.visitDartType(type!);
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(annotations, this);
+    v.transformTypeParameterList(typeParameters, this);
+    if (type != null) {
+      DartType newType = v.visitDartType(type!, dummyDartType);
+      if (identical(newType, dummyDartType)) {
+        type = null;
+      } else {
+        type = newType;
+      }
+    }
+  }
+
   void addAnnotation(Expression node) {
     if (annotations.isEmpty) {
       annotations = <Expression>[];
@@ -868,8 +946,9 @@
     node.parent = this;
   }
 
-  Location _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset);
+  @override
+  Location? _getLocationInEnclosingFile(int offset) {
+    return _getLocationInComponent(enclosingComponent, fileUri!, offset);
   }
 
   @override
@@ -943,6 +1022,7 @@
   ///
   /// This defaults to an immutable empty list. Use [addAnnotation] to add
   /// annotations if needed.
+  @override
   List<Expression> annotations = const <Expression>[];
 
   /// Name of the class.
@@ -952,7 +1032,8 @@
   /// The name may contain characters that are not valid in a Dart identifier,
   /// in particular, the symbol '&' is used in class names generated for mixin
   /// applications.
-  String name;
+  // TODO(johnniwinther): Make this non-nullable.
+  String? name;
 
   // Must match serialized bit positions.
   static const int FlagAbstract = 1 << 0;
@@ -1037,7 +1118,7 @@
     // Otherwise we have a left-linear binary tree (subtrees are supertype and
     // mixedInType) of constraints, where all the interior nodes are anonymous
     // mixin applications.
-    Supertype current = supertype;
+    Supertype? current = supertype;
     while (current != null && current.classNode.isAnonymousMixin) {
       Class currentClass = current.classNode;
       assert(currentClass.implementedTypes.length == 2);
@@ -1047,19 +1128,20 @@
       current =
           substitution.substituteSupertype(currentClass.implementedTypes[0]);
     }
-    return constraints..add(current);
+    return constraints..add(current!);
   }
 
   /// The URI of the source file this class was loaded from.
-  Uri fileUri;
+  @override
+  Uri? fileUri;
 
   final List<TypeParameter> typeParameters;
 
   /// The immediate super type, or `null` if this is the root class.
-  Supertype supertype;
+  Supertype? supertype;
 
   /// The mixed-in type if this is a mixin application, otherwise `null`.
-  Supertype mixedInType;
+  Supertype? mixedInType;
 
   /// The types from the `implements` clause.
   final List<Supertype> implementedTypes;
@@ -1069,14 +1151,14 @@
   /// If non-null, the function that will have to be called to fill-out the
   /// content of this class. Note that this should not be called directly
   /// though.
-  void Function() lazyBuilder;
+  void Function()? lazyBuilder;
 
   /// Makes sure the class is loaded, i.e. the fields, procedures etc have been
   /// loaded from the dill. Generally, one should not need to call this as it is
   /// done automatically when accessing the lists.
   void ensureLoaded() {
-    if (lazyBuilder != null) {
-      void Function() lazyBuilderLocal = lazyBuilder;
+    void Function()? lazyBuilderLocal = lazyBuilder;
+    if (lazyBuilderLocal != null) {
       lazyBuilder = null;
       lazyBuilderLocal();
     }
@@ -1086,7 +1168,7 @@
   ///
   /// Used for adding fields when reading the dill file.
   final List<Field> fieldsInternal;
-  DirtifyingList<Field> _fieldsView;
+  DirtifyingList<Field>? _fieldsView;
 
   /// Fields declared in the class.
   ///
@@ -1095,30 +1177,28 @@
     ensureLoaded();
     // If already dirty the caller just might as well add stuff directly too.
     if (dirty) return fieldsInternal;
-    _fieldsView ??= new DirtifyingList(this, fieldsInternal);
-    return _fieldsView;
+    return _fieldsView ??= new DirtifyingList(this, fieldsInternal);
   }
 
   /// Internal. Should *ONLY* be used from within kernel.
   ///
   /// Used for adding constructors when reading the dill file.
   final List<Constructor> constructorsInternal;
-  DirtifyingList<Constructor> _constructorsView;
+  DirtifyingList<Constructor>? _constructorsView;
 
   /// Constructors declared in the class.
   List<Constructor> get constructors {
     ensureLoaded();
     // If already dirty the caller just might as well add stuff directly too.
     if (dirty) return constructorsInternal;
-    _constructorsView ??= new DirtifyingList(this, constructorsInternal);
-    return _constructorsView;
+    return _constructorsView ??= new DirtifyingList(this, constructorsInternal);
   }
 
   /// Internal. Should *ONLY* be used from within kernel.
   ///
   /// Used for adding procedures when reading the dill file.
   final List<Procedure> proceduresInternal;
-  DirtifyingList<Procedure> _proceduresView;
+  DirtifyingList<Procedure>? _proceduresView;
 
   /// Procedures declared in the class.
   ///
@@ -1127,8 +1207,7 @@
     ensureLoaded();
     // If already dirty the caller just might as well add stuff directly too.
     if (dirty) return proceduresInternal;
-    _proceduresView ??= new DirtifyingList(this, proceduresInternal);
-    return _proceduresView;
+    return _proceduresView ??= new DirtifyingList(this, proceduresInternal);
   }
 
   /// Internal. Should *ONLY* be used from within kernel.
@@ -1137,7 +1216,7 @@
   /// file.
   final List<RedirectingFactoryConstructor>
       redirectingFactoryConstructorsInternal;
-  DirtifyingList<RedirectingFactoryConstructor>
+  DirtifyingList<RedirectingFactoryConstructor>?
       _redirectingFactoryConstructorsView;
 
   /// Redirecting factory constructors declared in the class.
@@ -1147,9 +1226,8 @@
     ensureLoaded();
     // If already dirty the caller just might as well add stuff directly too.
     if (dirty) return redirectingFactoryConstructorsInternal;
-    _redirectingFactoryConstructorsView ??=
+    return _redirectingFactoryConstructorsView ??=
         new DirtifyingList(this, redirectingFactoryConstructorsInternal);
-    return _redirectingFactoryConstructorsView;
   }
 
   Class(
@@ -1158,14 +1236,14 @@
       bool isAnonymousMixin: false,
       this.supertype,
       this.mixedInType,
-      List<TypeParameter> typeParameters,
-      List<Supertype> implementedTypes,
-      List<Constructor> constructors,
-      List<Procedure> procedures,
-      List<Field> fields,
-      List<RedirectingFactoryConstructor> redirectingFactoryConstructors,
+      List<TypeParameter>? typeParameters,
+      List<Supertype>? implementedTypes,
+      List<Constructor>? constructors,
+      List<Procedure>? procedures,
+      List<Field>? fields,
+      List<RedirectingFactoryConstructor>? redirectingFactoryConstructors,
       this.fileUri,
-      Reference reference})
+      Reference? reference})
       : this.typeParameters = typeParameters ?? <TypeParameter>[],
         this.implementedTypes = implementedTypes ?? <Supertype>[],
         this.fieldsInternal = fields ?? <Field>[],
@@ -1184,7 +1262,7 @@
   }
 
   void computeCanonicalNames() {
-    assert(canonicalName != null);
+    CanonicalName canonicalName = this.canonicalName!;
     if (!dirty) return;
     for (int i = 0; i < fields.length; ++i) {
       Field member = fields[i];
@@ -1192,7 +1270,7 @@
       if (member.hasSetter) {
         canonicalName
             .getChildFromFieldSetter(member)
-            .bindTo(member.setterReference);
+            .bindTo(member.setterReference!);
       }
     }
     for (int i = 0; i < procedures.length; ++i) {
@@ -1241,13 +1319,13 @@
   }
 
   /// The immediate super class, or `null` if this is the root class.
-  Class get superclass => supertype?.classNode;
+  Class? get superclass => supertype?.classNode;
 
   /// The mixed-in class if this is a mixin application, otherwise `null`.
   ///
   /// Note that this may itself be a mixin application.  Use [mixin] to get the
   /// class that has the fields and procedures.
-  Class get mixedInClass => mixedInType?.classNode;
+  Class? get mixedInClass => mixedInType?.classNode;
 
   /// The class that declares the field and procedures of this class.
   Class get mixin => mixedInClass?.mixin ?? this;
@@ -1256,18 +1334,18 @@
 
   String get demangledName {
     if (isAnonymousMixin) return nameAsMixinApplication;
-    assert(!name.contains('&'));
-    return name;
+    assert(!name!.contains('&'));
+    return name!;
   }
 
   String get nameAsMixinApplication {
     assert(isAnonymousMixin);
-    return demangleMixinApplicationName(name);
+    return demangleMixinApplicationName(name!);
   }
 
   String get nameAsMixinApplicationSubclass {
     assert(isAnonymousMixin);
-    return demangleMixinApplicationSubclassName(name);
+    return demangleMixinApplicationSubclassName(name!);
   }
 
   /// Members declared in this class.
@@ -1286,13 +1364,13 @@
   /// This getter is for convenience, not efficiency.  Consider manually
   /// iterating the super types to speed up code in production.
   Iterable<Supertype> get supers => <Iterable<Supertype>>[
-        supertype == null ? const [] : [supertype],
-        mixedInType == null ? const [] : [mixedInType],
+        supertype == null ? const [] : [supertype!],
+        mixedInType == null ? const [] : [mixedInType!],
         implementedTypes
       ].expand((x) => x);
 
   /// The library containing this class.
-  Library get enclosingLibrary => parent;
+  Library get enclosingLibrary => parent as Library;
 
   /// Internal. Should *ONLY* be used from within kernel.
   ///
@@ -1329,6 +1407,7 @@
     redirectingFactoryConstructorsInternal.add(redirectingFactoryConstructor);
   }
 
+  @override
   void addAnnotation(Expression node) {
     if (annotations.isEmpty) {
       annotations = <Expression>[];
@@ -1337,7 +1416,12 @@
     node.parent = this;
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitClass(this);
+
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitClass(this, arg);
+
   R acceptReference<R>(Visitor<R> v) => v.visitClassReference(this);
 
   Supertype get asRawSupertype {
@@ -1363,7 +1447,8 @@
     printer.writeClassName(reference);
   }
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
     visitList(typeParameters, v);
     supertype?.accept(v);
@@ -1375,24 +1460,54 @@
     visitList(redirectingFactoryConstructors, v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(annotations, v, this);
-    transformList(typeParameters, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(annotations, this);
+    v.transformList(typeParameters, this);
     if (supertype != null) {
-      supertype = v.visitSupertype(supertype);
+      supertype = v.visitSupertype(supertype!);
     }
     if (mixedInType != null) {
-      mixedInType = v.visitSupertype(mixedInType);
+      mixedInType = v.visitSupertype(mixedInType!);
     }
-    transformSupertypeList(implementedTypes, v);
-    transformList(constructors, v, this);
-    transformList(procedures, v, this);
-    transformList(fields, v, this);
-    transformList(redirectingFactoryConstructors, v, this);
+    v.transformSupertypeList(implementedTypes);
+    v.transformList(constructors, this);
+    v.transformList(procedures, this);
+    v.transformList(fields, this);
+    v.transformList(redirectingFactoryConstructors, this);
   }
 
-  Location _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset);
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(annotations, this);
+    v.transformTypeParameterList(typeParameters, this);
+    if (supertype != null) {
+      Supertype newSupertype = v.visitSupertype(supertype!, dummySupertype);
+      if (identical(newSupertype, dummySupertype)) {
+        supertype = null;
+      } else {
+        supertype = newSupertype;
+      }
+    }
+    if (mixedInType != null) {
+      Supertype newMixedInType = v.visitSupertype(mixedInType!, dummySupertype);
+      if (identical(newMixedInType, dummySupertype)) {
+        mixedInType = null;
+      } else {
+        mixedInType = newMixedInType;
+      }
+    }
+    v.transformSupertypeList(implementedTypes);
+    v.transformConstructorList(constructors, this);
+    v.transformProcedureList(procedures, this);
+    v.transformFieldList(fields, this);
+    v.transformRedirectingFactoryConstructorList(
+        redirectingFactoryConstructors, this);
+  }
+
+  @override
+  Location? _getLocationInEnclosingFile(int offset) {
+    return _getLocationInComponent(enclosingComponent, fileUri!, offset);
   }
 }
 
@@ -1405,10 +1520,11 @@
   ///
   /// If unnamed, the extension will be given a synthesized name by the
   /// front end.
-  String name;
+  // TODO(johnniwinther): Make this non-nullable.
+  String? name;
 
   /// The URI of the source file this class was loaded from.
-  Uri fileUri;
+  Uri? fileUri;
 
   /// Type parameters declared on the extension.
   final List<TypeParameter> typeParameters;
@@ -1420,7 +1536,8 @@
   ///   class A {}
   ///   extension B on A {}
   ///
-  DartType onType;
+  // TODO(johnniwinther): Should this be late non-nullable?
+  DartType? onType;
 
   /// The members declared by the extension.
   ///
@@ -1430,39 +1547,55 @@
 
   Extension(
       {this.name,
-      List<TypeParameter> typeParameters,
+      List<TypeParameter>? typeParameters,
       this.onType,
-      List<ExtensionMemberDescriptor> members,
+      List<ExtensionMemberDescriptor>? members,
       this.fileUri,
-      Reference reference})
+      Reference? reference})
       : this.typeParameters = typeParameters ?? <TypeParameter>[],
         this.members = members ?? <ExtensionMemberDescriptor>[],
         super(reference) {
     setParents(this.typeParameters, this);
   }
 
-  Library get enclosingLibrary => parent;
+  Library get enclosingLibrary => parent as Library;
 
   @override
   R accept<R>(TreeVisitor<R> v) => v.visitExtension(this);
 
   @override
-  visitChildren(Visitor v) {
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitExtension(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(typeParameters, v);
     onType?.accept(v);
   }
 
   @override
-  transformChildren(Transformer v) {
-    transformList(typeParameters, v, this);
+  void transformChildren(Transformer v) {
+    v.transformList(typeParameters, this);
     if (onType != null) {
-      onType = v.visitDartType(onType);
+      onType = v.visitDartType(onType!);
     }
   }
 
   @override
-  Location _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset);
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformTypeParameterList(typeParameters, this);
+    if (onType != null) {
+      DartType newOnType = v.visitDartType(onType!, dummyDartType);
+      if (identical(newOnType, dummyDartType)) {
+        onType = null;
+      } else {
+        onType = newOnType;
+      }
+    }
+  }
+
+  @override
+  Location? _getLocationInEnclosingFile(int offset) {
+    return _getLocationInComponent(enclosingComponent, fileUri!, offset);
   }
 
   @override
@@ -1521,10 +1654,13 @@
   int flags = 0;
 
   /// Reference to the top-level member created for the extension method.
-  Reference member;
+  final Reference member;
 
   ExtensionMemberDescriptor(
-      {this.name, this.kind, bool isStatic: false, this.member}) {
+      {required this.name,
+      required this.kind,
+      bool isStatic: false,
+      required this.member}) {
     this.isStatic = isStatic;
   }
 
@@ -1558,12 +1694,15 @@
   ///
   /// This defaults to an immutable empty list. Use [addAnnotation] to add
   /// annotations if needed.
+  @override
   List<Expression> annotations = const <Expression>[];
 
-  Name name;
+  // TODO(johnniwinther): Make this non-nullable.
+  Name? name;
 
   /// The URI of the source file this member was loaded from.
-  Uri fileUri;
+  @override
+  Uri? fileUri;
 
   /// Flags summarizing the kinds of AST nodes contained in this member, for
   /// speeding up transformations that only affect certain types of nodes.
@@ -1582,13 +1721,19 @@
   // TODO(asgerf): It might be worthwhile to put this on classes as well.
   int transformerFlags = 0;
 
-  Member(this.name, this.fileUri, Reference reference) : super(reference);
+  Member(this.name, this.fileUri, Reference? reference) : super(reference);
 
-  Class get enclosingClass => parent is Class ? parent : null;
-  Library get enclosingLibrary => parent is Class ? parent.parent : parent;
+  Class? get enclosingClass => parent is Class ? parent as Class : null;
+  Library get enclosingLibrary =>
+      (parent is Class ? parent!.parent : parent) as Library;
 
+  @override
   R accept<R>(MemberVisitor<R> v);
-  acceptReference(MemberReferenceVisitor v);
+
+  @override
+  R accept1<R, A>(MemberVisitor1<R, A> v, A arg);
+
+  R acceptReference<R>(MemberReferenceVisitor<R> v);
 
   /// Returns true if this is an abstract procedure.
   bool get isAbstract => false;
@@ -1635,8 +1780,9 @@
   bool get isNonNullableByDefault;
   void set isNonNullableByDefault(bool value);
 
-  /// The body of the procedure or constructor, or `null` if this is a field.
-  FunctionNode get function => null;
+  /// The function signature and body of the procedure or constructor, or `null`
+  /// if this is a field.
+  FunctionNode? get function => null;
 
   /// Returns a possibly synthesized name for this member, consistent with
   /// the names used across all [toString] calls.
@@ -1648,6 +1794,7 @@
     printer.writeMemberName(reference);
   }
 
+  @override
   void addAnnotation(Expression node) {
     if (annotations.isEmpty) {
       annotations = <Expression>[];
@@ -1665,7 +1812,7 @@
 
   /// If this member is a member signature, [memberSignatureOrigin] is one of
   /// the non-member signature members from which it was created.
-  Member get memberSignatureOrigin => null;
+  Member? get memberSignatureOrigin => null;
 }
 
 /// A field declaration.
@@ -1675,17 +1822,22 @@
 class Field extends Member {
   DartType type; // Not null. Defaults to DynamicType.
   int flags = 0;
-  Expression initializer; // May be null.
-  final Reference setterReference;
+  Expression? initializer; // May be null.
+  final Reference? setterReference;
+
+  @override
   @Deprecated("Use the specific getterReference/setterReference instead")
   Reference get reference => super.reference;
 
   Reference get getterReference => super.reference;
+
+  @override
   @Deprecated(
       "Use the specific getterCanonicalName/setterCanonicalName instead")
-  CanonicalName get canonicalName => reference?.canonicalName;
-  CanonicalName get getterCanonicalName => getterReference?.canonicalName;
-  CanonicalName get setterCanonicalName => setterReference?.canonicalName;
+  CanonicalName? get canonicalName => reference.canonicalName;
+
+  CanonicalName? get getterCanonicalName => getterReference.canonicalName;
+  CanonicalName? get setterCanonicalName => setterReference?.canonicalName;
 
   Field.mutable(Name name,
       {this.type: const DynamicType(),
@@ -1695,12 +1847,13 @@
       bool isStatic: false,
       bool isLate: false,
       int transformerFlags: 0,
-      Uri fileUri,
-      Reference getterReference,
-      Reference setterReference})
+      Uri? fileUri,
+      Reference? getterReference,
+      Reference? setterReference})
       : this.setterReference = setterReference ?? new Reference(),
         super(name, fileUri, getterReference) {
-    this.setterReference.node = this;
+    this.setterReference!.node = this;
+    // ignore: unnecessary_null_comparison
     assert(type != null);
     initializer?.parent = this;
     this.isCovariant = isCovariant;
@@ -1719,10 +1872,11 @@
       bool isStatic: false,
       bool isLate: false,
       int transformerFlags: 0,
-      Uri fileUri,
-      Reference getterReference})
+      Uri? fileUri,
+      Reference? getterReference})
       : this.setterReference = null,
         super(name, fileUri, getterReference) {
+    // ignore: unnecessary_null_comparison
     assert(type != null);
     initializer?.parent = this;
     this.isCovariant = isCovariant;
@@ -1737,7 +1891,7 @@
   void _relinkNode() {
     super._relinkNode();
     if (hasSetter) {
-      this.setterReference.node = this;
+      this.setterReference!.node = this;
     }
   }
 
@@ -1755,7 +1909,10 @@
   bool get isCovariant => flags & FlagCovariant != 0;
 
   bool get isFinal => flags & FlagFinal != 0;
+
+  @override
   bool get isConst => flags & FlagConst != 0;
+
   bool get isStatic => flags & FlagStatic != 0;
 
   @override
@@ -1815,11 +1972,19 @@
         : (flags & ~FlagInternalImplementation);
   }
 
+  @override
   bool get isInstanceMember => !isStatic;
+
+  @override
   bool get hasGetter => true;
+
+  @override
   bool get hasSetter => setterReference != null;
 
+  @override
   bool get isExternal => false;
+
+  @override
   void set isExternal(bool value) {
     if (value) throw 'Fields cannot be external';
   }
@@ -1834,31 +1999,53 @@
         : (flags & ~FlagNonNullableByDefault);
   }
 
+  @override
   R accept<R>(MemberVisitor<R> v) => v.visitField(this);
 
-  acceptReference(MemberReferenceVisitor v) => v.visitFieldReference(this);
+  @override
+  R accept1<R, A>(MemberVisitor1<R, A> v, A arg) => v.visitField(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  R acceptReference<R>(MemberReferenceVisitor<R> v) =>
+      v.visitFieldReference(this);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
-    type?.accept(v);
+    type.accept(v);
     name?.accept(v);
     initializer?.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     type = v.visitDartType(type);
-    transformList(annotations, v, this);
+    v.transformList(annotations, this);
     if (initializer != null) {
-      initializer = initializer.accept<TreeNode>(v);
+      initializer = v.transform(initializer!);
       initializer?.parent = this;
     }
   }
 
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    type = v.visitDartType(type, null);
+    v.transformExpressionList(annotations, this);
+    if (initializer != null) {
+      initializer = v.transformOrRemoveExpression(initializer!);
+      initializer?.parent = this;
+    }
+  }
+
+  @override
   DartType get getterType => type;
+
+  @override
   DartType get setterType => hasSetter ? type : const BottomType();
 
-  Location _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset);
+  @override
+  Location? _getLocationInEnclosingFile(int offset) {
+    return _getLocationInComponent(enclosingComponent, fileUri!, offset);
   }
 
   @override
@@ -1886,18 +2073,22 @@
   int startFileOffset = TreeNode.noOffset;
 
   int flags = 0;
-  FunctionNode function;
+
+  // TODO(johnniwinther): Make this non-nullable.
+  @override
+  FunctionNode? function;
+
   List<Initializer> initializers;
 
   Constructor(this.function,
-      {Name name,
+      {Name? name,
       bool isConst: false,
       bool isExternal: false,
       bool isSynthetic: false,
-      List<Initializer> initializers,
+      List<Initializer>? initializers,
       int transformerFlags: 0,
-      Uri fileUri,
-      Reference reference})
+      Uri? fileUri,
+      Reference? reference})
       : this.initializers = initializers ?? <Initializer>[],
         super(name, fileUri, reference) {
     function?.parent = this;
@@ -1913,7 +2104,10 @@
   static const int FlagSynthetic = 1 << 2;
   static const int FlagNonNullableByDefault = 1 << 3;
 
+  @override
   bool get isConst => flags & FlagConst != 0;
+
+  @override
   bool get isExternal => flags & FlagExternal != 0;
 
   /// True if this is a synthetic constructor inserted in a class that
@@ -1924,6 +2118,7 @@
     flags = value ? (flags | FlagConst) : (flags & ~FlagConst);
   }
 
+  @override
   void set isExternal(bool value) {
     flags = value ? (flags | FlagExternal) : (flags & ~FlagExternal);
   }
@@ -1932,8 +2127,13 @@
     flags = value ? (flags | FlagSynthetic) : (flags & ~FlagSynthetic);
   }
 
+  @override
   bool get isInstanceMember => false;
+
+  @override
   bool get hasGetter => false;
+
+  @override
   bool get hasSetter => false;
 
   @override
@@ -1949,32 +2149,54 @@
         : (flags & ~FlagNonNullableByDefault);
   }
 
+  @override
   R accept<R>(MemberVisitor<R> v) => v.visitConstructor(this);
 
-  acceptReference(MemberReferenceVisitor v) =>
+  @override
+  R accept1<R, A>(MemberVisitor1<R, A> v, A arg) =>
+      v.visitConstructor(this, arg);
+
+  @override
+  R acceptReference<R>(MemberReferenceVisitor<R> v) =>
       v.visitConstructorReference(this);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
     name?.accept(v);
     visitList(initializers, v);
     function?.accept(v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(annotations, v, this);
-    transformList(initializers, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(annotations, this);
+    v.transformList(initializers, this);
     if (function != null) {
-      function = function.accept<TreeNode>(v);
+      function = v.transform(function!);
       function?.parent = this;
     }
   }
 
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(annotations, this);
+    v.transformInitializerList(initializers, this);
+    if (function != null) {
+      function = v.transformOrRemove(function!, dummyFunctionNode);
+      function?.parent = this;
+    }
+  }
+
+  @override
   DartType get getterType => const BottomType();
+
+  @override
   DartType get setterType => const BottomType();
 
-  Location _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset);
+  @override
+  Location? _getLocationInEnclosingFile(int offset) {
+    return _getLocationInComponent(enclosingComponent, fileUri!, offset);
   }
 }
 
@@ -2009,7 +2231,7 @@
 
   /// Reference to the constructor or the factory that this
   /// [RedirectingFactoryConstructor] redirects to.
-  Reference targetReference;
+  Reference? targetReference;
 
   /// [typeParameters] are duplicates of the type parameters of the enclosing
   /// class.  Because [RedirectingFactoryConstructor]s aren't instance members,
@@ -2028,17 +2250,17 @@
   List<VariableDeclaration> namedParameters;
 
   RedirectingFactoryConstructor(this.targetReference,
-      {Name name,
+      {Name? name,
       bool isConst: false,
       bool isExternal: false,
       int transformerFlags: 0,
-      List<DartType> typeArguments,
-      List<TypeParameter> typeParameters,
-      List<VariableDeclaration> positionalParameters,
-      List<VariableDeclaration> namedParameters,
-      int requiredParameterCount,
-      Uri fileUri,
-      Reference reference})
+      List<DartType>? typeArguments,
+      List<TypeParameter>? typeParameters,
+      List<VariableDeclaration>? positionalParameters,
+      List<VariableDeclaration>? namedParameters,
+      int? requiredParameterCount,
+      Uri? fileUri,
+      Reference? reference})
       : this.typeArguments = typeArguments ?? <DartType>[],
         this.typeParameters = typeParameters ?? <TypeParameter>[],
         this.positionalParameters =
@@ -2059,19 +2281,28 @@
   static const int FlagExternal = 1 << 1;
   static const int FlagNonNullableByDefault = 1 << 2;
 
+  @override
   bool get isConst => flags & FlagConst != 0;
+
+  @override
   bool get isExternal => flags & FlagExternal != 0;
 
   void set isConst(bool value) {
     flags = value ? (flags | FlagConst) : (flags & ~FlagConst);
   }
 
+  @override
   void set isExternal(bool value) {
     flags = value ? (flags | FlagExternal) : (flags & ~FlagExternal);
   }
 
+  @override
   bool get isInstanceMember => false;
+
+  @override
   bool get hasGetter => false;
+
+  @override
   bool get hasSetter => false;
 
   @override
@@ -2089,36 +2320,54 @@
         : (flags & ~FlagNonNullableByDefault);
   }
 
-  Member get target => targetReference?.asMember;
+  Member? get target => targetReference?.asMember;
 
-  void set target(Member member) {
+  void set target(Member? member) {
     assert(member is Constructor ||
         (member is Procedure && member.kind == ProcedureKind.Factory));
     targetReference = getMemberReferenceGetter(member);
   }
 
+  @override
   R accept<R>(MemberVisitor<R> v) => v.visitRedirectingFactoryConstructor(this);
 
-  acceptReference(MemberReferenceVisitor v) =>
+  @override
+  R accept1<R, A>(MemberVisitor1<R, A> v, A arg) =>
+      v.visitRedirectingFactoryConstructor(this, arg);
+
+  @override
+  R acceptReference<R>(MemberReferenceVisitor<R> v) =>
       v.visitRedirectingFactoryConstructorReference(this);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
     target?.acceptReference(v);
     visitList(typeArguments, v);
     name?.accept(v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(annotations, v, this);
-    transformTypeList(typeArguments, v);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(annotations, this);
+    v.transformDartTypeList(typeArguments);
   }
 
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(annotations, this);
+    v.transformDartTypeList(typeArguments);
+  }
+
+  @override
   DartType get getterType => const BottomType();
+
+  @override
   DartType get setterType => const BottomType();
 
-  Location _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset);
+  @override
+  Location? _getLocationInEnclosingFile(int offset) {
+    return _getLocationInComponent(enclosingComponent, fileUri!, offset);
   }
 }
 
@@ -2333,12 +2582,15 @@
 
   final ProcedureKind kind;
   int flags = 0;
-  // function is null if and only if abstract, external.
-  FunctionNode function;
+
+  // TODO(johnniwinther): Make this non-nullable.
+  @override
+  FunctionNode? function;
 
   // The function node's body might be lazily loaded, meaning that this value
   // might not be set correctly yet. Make sure the body is loaded before
   // returning anything.
+  @override
   int get transformerFlags {
     function?.body;
     return super.transformerFlags;
@@ -2347,6 +2599,7 @@
   // The function node's body might be lazily loaded, meaning that this value
   // might get overwritten later (when the body is read). To avoid that read the
   // body now and only set the value afterwards.
+  @override
   void set transformerFlags(int newValue) {
     function?.body;
     super.transformerFlags = newValue;
@@ -2360,7 +2613,7 @@
   }
 
   ProcedureStubKind stubKind;
-  Reference stubTargetReference;
+  Reference? stubTargetReference;
 
   Procedure(Name name, ProcedureKind kind, FunctionNode function,
       {bool isAbstract: false,
@@ -2370,10 +2623,10 @@
       bool isExtensionMember: false,
       bool isSynthetic: false,
       int transformerFlags: 0,
-      Uri fileUri,
-      Reference reference,
+      Uri? fileUri,
+      Reference? reference,
       ProcedureStubKind stubKind: ProcedureStubKind.Regular,
-      Member stubTarget})
+      Member? stubTarget})
       : this._byReferenceRenamed(name, kind, function,
             isAbstract: isAbstract,
             isStatic: isStatic,
@@ -2396,10 +2649,11 @@
       bool isExtensionMember: false,
       bool isSynthetic: false,
       int transformerFlags: 0,
-      Uri fileUri,
-      Reference reference,
+      Uri? fileUri,
+      Reference? reference,
       this.stubKind: ProcedureStubKind.Regular,
       this.stubTargetReference})
+      // ignore: unnecessary_null_comparison
       : assert(kind != null),
         super(name, fileUri, reference) {
     function?.parent = this;
@@ -2430,11 +2684,16 @@
   static const int FlagSynthetic = 1 << 7;
 
   bool get isStatic => flags & FlagStatic != 0;
+
+  @override
   bool get isAbstract => flags & FlagAbstract != 0;
+
+  @override
   bool get isExternal => flags & FlagExternal != 0;
 
   /// True if this has the `const` modifier.  This is only possible for external
   /// constant factories, such as `String.fromEnvironment`.
+  @override
   bool get isConst => flags & FlagConst != 0;
 
   /// If set, this flag indicates that this function's implementation exists
@@ -2488,6 +2747,7 @@
     flags = value ? (flags | FlagAbstract) : (flags & ~FlagAbstract);
   }
 
+  @override
   void set isExternal(bool value) {
     flags = value ? (flags | FlagExternal) : (flags & ~FlagExternal);
   }
@@ -2511,12 +2771,19 @@
     flags = value ? (flags | FlagSynthetic) : (flags & ~FlagSynthetic);
   }
 
+  @override
   bool get isInstanceMember => !isStatic;
+
   bool get isGetter => kind == ProcedureKind.Getter;
   bool get isSetter => kind == ProcedureKind.Setter;
   bool get isAccessor => isGetter || isSetter;
+
+  @override
   bool get hasGetter => kind != ProcedureKind.Setter;
+
+  @override
   bool get hasSetter => kind == ProcedureKind.Setter;
+
   bool get isFactory => kind == ProcedureKind.Factory;
 
   @override
@@ -2529,59 +2796,80 @@
         : (flags & ~FlagNonNullableByDefault);
   }
 
-  Member get concreteForwardingStubTarget =>
+  Member? get concreteForwardingStubTarget =>
       stubKind == ProcedureStubKind.ConcreteForwardingStub
           ? stubTargetReference?.asMember
           : null;
 
-  Member get abstractForwardingStubTarget =>
+  Member? get abstractForwardingStubTarget =>
       stubKind == ProcedureStubKind.AbstractForwardingStub
           ? stubTargetReference?.asMember
           : null;
 
-  Member get stubTarget => stubTargetReference?.asMember;
+  Member? get stubTarget => stubTargetReference?.asMember;
 
-  void set stubTarget(Member target) {
+  void set stubTarget(Member? target) {
     stubTargetReference = getMemberReferenceBasedOnProcedureKind(target, kind);
   }
 
-  Member get memberSignatureOrigin =>
+  @override
+  Member? get memberSignatureOrigin =>
       stubKind == ProcedureStubKind.MemberSignature
           ? stubTargetReference?.asMember
           : null;
 
+  @override
   R accept<R>(MemberVisitor<R> v) => v.visitProcedure(this);
 
-  acceptReference(MemberReferenceVisitor v) => v.visitProcedureReference(this);
+  @override
+  R accept1<R, A>(MemberVisitor1<R, A> v, A arg) => v.visitProcedure(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  R acceptReference<R>(MemberReferenceVisitor<R> v) =>
+      v.visitProcedureReference(this);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
     name?.accept(v);
     function?.accept(v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(annotations, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(annotations, this);
     if (function != null) {
-      function = function.accept<TreeNode>(v);
+      function = v.transform(function!);
       function?.parent = this;
     }
   }
 
-  DartType get getterType {
-    return isGetter
-        ? function.returnType
-        : function.computeFunctionType(enclosingLibrary.nonNullable);
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(annotations, this);
+    if (function != null) {
+      function = v.transformOrRemove(function!, dummyFunctionNode);
+      function?.parent = this;
+    }
   }
 
+  @override
+  DartType get getterType {
+    return isGetter
+        ? function!.returnType
+        : function!.computeFunctionType(enclosingLibrary.nonNullable);
+  }
+
+  @override
   DartType get setterType {
     return isSetter
-        ? function.positionalParameters[0].type
+        ? function!.positionalParameters[0].type
         : const BottomType();
   }
 
-  Location _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset);
+  @override
+  Location? _getLocationInEnclosingFile(int offset) {
+    return _getLocationInComponent(enclosingComponent, fileUri!, offset);
   }
 }
 
@@ -2603,7 +2891,11 @@
   @informative
   bool isSynthetic = false;
 
+  @override
   R accept<R>(InitializerVisitor<R> v);
+
+  @override
+  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg);
 }
 
 /// An initializer with a compile-time error.
@@ -2613,10 +2905,21 @@
 // DESIGN TODO: The frontend should use this in a lot more cases to catch
 // invalid cases.
 class InvalidInitializer extends Initializer {
+  @override
   R accept<R>(InitializerVisitor<R> v) => v.visitInvalidInitializer(this);
 
-  visitChildren(Visitor v) {}
-  transformChildren(Transformer v) {}
+  @override
+  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
+      v.visitInvalidInitializer(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -2645,30 +2948,47 @@
   FieldInitializer(Field field, Expression value)
       : this.byReference(
             // getterReference is used since this refers to the field itself
-            field?.getterReference,
+            field.getterReference,
             value);
 
   FieldInitializer.byReference(this.fieldReference, this.value) {
-    value?.parent = this;
+    value.parent = this;
   }
 
-  Field get field => fieldReference?.node;
+  Field get field => fieldReference.asField;
 
   void set field(Field field) {
-    fieldReference = field?.getterReference;
+    fieldReference = field.getterReference;
   }
 
+  @override
   R accept<R>(InitializerVisitor<R> v) => v.visitFieldInitializer(this);
 
-  visitChildren(Visitor v) {
-    field?.acceptReference(v);
-    value?.accept(v);
+  @override
+  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
+      v.visitFieldInitializer(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
+    field.acceptReference(v);
+    value.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (value != null) {
-      value = value.accept<TreeNode>(v);
-      value?.parent = this;
+      value = v.transform(value);
+      value.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (value != null) {
+      value = v.transform(value);
+      value.parent = this;
     }
   }
 
@@ -2700,31 +3020,48 @@
   SuperInitializer(Constructor target, Arguments arguments)
       : this.byReference(
             // Getter vs setter doesn't matter for constructors.
-            getMemberReferenceGetter(target),
+            getNonNullableMemberReferenceGetter(target),
             arguments);
 
   SuperInitializer.byReference(this.targetReference, this.arguments) {
-    arguments?.parent = this;
+    arguments.parent = this;
   }
 
-  Constructor get target => targetReference?.asConstructor;
+  Constructor get target => targetReference.asConstructor;
 
   void set target(Constructor target) {
     // Getter vs setter doesn't matter for constructors.
-    targetReference = getMemberReferenceGetter(target);
+    targetReference = getNonNullableMemberReferenceGetter(target);
   }
 
+  @override
   R accept<R>(InitializerVisitor<R> v) => v.visitSuperInitializer(this);
 
-  visitChildren(Visitor v) {
-    target?.acceptReference(v);
-    arguments?.accept(v);
+  @override
+  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
+      v.visitSuperInitializer(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
+    target.acceptReference(v);
+    arguments.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
-      arguments?.parent = this;
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
     }
   }
 
@@ -2752,31 +3089,48 @@
   RedirectingInitializer(Constructor target, Arguments arguments)
       : this.byReference(
             // Getter vs setter doesn't matter for constructors.
-            getMemberReferenceGetter(target),
+            getNonNullableMemberReferenceGetter(target),
             arguments);
 
   RedirectingInitializer.byReference(this.targetReference, this.arguments) {
-    arguments?.parent = this;
+    arguments.parent = this;
   }
 
-  Constructor get target => targetReference?.asConstructor;
+  Constructor get target => targetReference.asConstructor;
 
   void set target(Constructor target) {
     // Getter vs setter doesn't matter for constructors.
-    targetReference = getMemberReferenceGetter(target);
+    targetReference = getNonNullableMemberReferenceGetter(target);
   }
 
+  @override
   R accept<R>(InitializerVisitor<R> v) => v.visitRedirectingInitializer(this);
 
-  visitChildren(Visitor v) {
-    target?.acceptReference(v);
-    arguments?.accept(v);
+  @override
+  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
+      v.visitRedirectingInitializer(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
+    target.acceptReference(v);
+    arguments.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
-      arguments?.parent = this;
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
     }
   }
 
@@ -2799,19 +3153,36 @@
   VariableDeclaration variable;
 
   LocalInitializer(this.variable) {
-    variable?.parent = this;
+    variable.parent = this;
   }
 
+  @override
   R accept<R>(InitializerVisitor<R> v) => v.visitLocalInitializer(this);
 
-  visitChildren(Visitor v) {
-    variable?.accept(v);
+  @override
+  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
+      v.visitLocalInitializer(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
+    variable.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
-      variable?.parent = this;
+      variable = v.transform(variable);
+      variable.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (variable != null) {
+      variable = v.transform(variable);
+      variable.parent = this;
     }
   }
 
@@ -2833,14 +3204,27 @@
     statement.parent = this;
   }
 
+  @override
   R accept<R>(InitializerVisitor<R> v) => v.visitAssertInitializer(this);
 
-  visitChildren(Visitor v) {
+  @override
+  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
+      v.visitAssertInitializer(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
     statement.accept(v);
   }
 
-  transformChildren(Transformer v) {
-    statement = statement.accept<TreeNode>(v);
+  @override
+  void transformChildren(Transformer v) {
+    statement = v.transform(statement);
+    statement.parent = this;
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    statement = v.transform(statement);
     statement.parent = this;
   }
 
@@ -2890,7 +3274,7 @@
   List<VariableDeclaration> positionalParameters;
   List<VariableDeclaration> namedParameters;
   DartType returnType; // Not null.
-  Statement _body;
+  Statement? _body;
 
   /// The future value type of this is an async function, otherwise `null`.
   ///
@@ -2903,55 +3287,56 @@
   /// here the return types are `Future<Foo>` and `FutureOr<Foo>` for `method1`
   /// and `method2`, respectively, but the future value type is in both cases
   /// `Foo`.
-  DartType futureValueType;
+  DartType? futureValueType;
 
-  void Function() lazyBuilder;
+  void Function()? lazyBuilder;
 
   void _buildLazy() {
-    if (lazyBuilder != null) {
-      void Function() lazyBuilderLocal = lazyBuilder;
+    void Function()? lazyBuilderLocal = lazyBuilder;
+    if (lazyBuilderLocal != null) {
       lazyBuilder = null;
       lazyBuilderLocal();
     }
   }
 
-  Statement get body {
+  Statement? get body {
     _buildLazy();
     return _body;
   }
 
-  void set body(Statement body) {
+  void set body(Statement? body) {
     _buildLazy();
     _body = body;
   }
 
   FunctionNode(this._body,
-      {List<TypeParameter> typeParameters,
-      List<VariableDeclaration> positionalParameters,
-      List<VariableDeclaration> namedParameters,
-      int requiredParameterCount,
+      {List<TypeParameter>? typeParameters,
+      List<VariableDeclaration>? positionalParameters,
+      List<VariableDeclaration>? namedParameters,
+      int? requiredParameterCount,
       this.returnType: const DynamicType(),
       this.asyncMarker: AsyncMarker.Sync,
-      this.dartAsyncMarker,
+      AsyncMarker? dartAsyncMarker,
       this.futureValueType})
       : this.positionalParameters =
             positionalParameters ?? <VariableDeclaration>[],
         this.requiredParameterCount =
             requiredParameterCount ?? positionalParameters?.length ?? 0,
         this.namedParameters = namedParameters ?? <VariableDeclaration>[],
-        this.typeParameters = typeParameters ?? <TypeParameter>[] {
+        this.typeParameters = typeParameters ?? <TypeParameter>[],
+        this.dartAsyncMarker = dartAsyncMarker ?? asyncMarker {
+    // ignore: unnecessary_null_comparison
     assert(returnType != null);
     setParents(this.typeParameters, this);
     setParents(this.positionalParameters, this);
     setParents(this.namedParameters, this);
     _body?.parent = this;
-    dartAsyncMarker ??= asyncMarker;
   }
 
   static DartType _getTypeOfVariable(VariableDeclaration node) => node.type;
 
   static NamedType _getNamedTypeOfVariable(VariableDeclaration node) {
-    return new NamedType(node.name, node.type, isRequired: node.isRequired);
+    return new NamedType(node.name!, node.type, isRequired: node.isRequired);
   }
 
   /// Returns the function type of the node reusing its type parameters.
@@ -2963,7 +3348,7 @@
   /// type of the enclosing generic function and in combination with
   /// [FunctionType.withoutTypeParameters].
   FunctionType computeThisFunctionType(Nullability nullability) {
-    TreeNode parent = this.parent;
+    TreeNode? parent = this.parent;
     List<NamedType> named =
         namedParameters.map(_getNamedTypeOfVariable).toList(growable: false);
     named.sort();
@@ -2971,7 +3356,7 @@
     // transformations like erasure don't work.
     List<TypeParameter> typeParametersCopy = new List<TypeParameter>.from(
         parent is Constructor
-            ? parent.enclosingClass.typeParameters
+            ? parent.enclosingClass!.typeParameters
             : typeParameters);
     return new FunctionType(
         positionalParameters.map(_getTypeOfVariable).toList(growable: false),
@@ -3006,13 +3391,12 @@
   /// constructor invocations.
   FunctionType computeAliasedConstructorFunctionType(
       Typedef typedef, Library library) {
-    TreeNode parent = this.parent;
     assert(parent is Constructor, "Only run this method on constructors");
-    Constructor parentConstructor = parent;
+    Constructor parentConstructor = parent as Constructor;
     // We need create a copy of the list of type parameters, otherwise
     // transformations like erasure don't work.
     List<TypeParameter> classTypeParametersCopy =
-        List.from(parentConstructor.enclosingClass.typeParameters);
+        List.from(parentConstructor.enclosingClass!.typeParameters);
     List<TypeParameter> typedefTypeParametersCopy =
         List.from(typedef.typeParameters);
     List<DartType> asTypeArguments =
@@ -3022,7 +3406,7 @@
     DartType unaliasedTypedef = typedefType.unalias;
     assert(unaliasedTypedef is InterfaceType,
         "[typedef] is assumed to resolve to an interface type");
-    InterfaceType targetType = unaliasedTypedef;
+    InterfaceType targetType = unaliasedTypedef as InterfaceType;
     Substitution substitution = Substitution.fromPairs(
         classTypeParametersCopy, targetType.typeArguments);
     List<DartType> positional = positionalParameters
@@ -3031,7 +3415,7 @@
         .toList(growable: false);
     List<NamedType> named = namedParameters
         .map((VariableDeclaration decl) => NamedType(
-            decl.name, substitution.substituteType(decl.type),
+            decl.name!, substitution.substituteType(decl.type),
             isRequired: decl.isRequired))
         .toList(growable: false);
     named.sort();
@@ -3066,7 +3450,7 @@
     DartType unaliasedTypedef = typedefType.unalias;
     assert(unaliasedTypedef is InterfaceType,
         "[typedef] is assumed to resolve to an interface type");
-    InterfaceType targetType = unaliasedTypedef;
+    InterfaceType targetType = unaliasedTypedef as InterfaceType;
     Substitution substitution = Substitution.fromPairs(
         classTypeParametersCopy, targetType.typeArguments);
     List<DartType> positional = positionalParameters
@@ -3075,7 +3459,7 @@
         .toList(growable: false);
     List<NamedType> named = namedParameters
         .map((VariableDeclaration decl) => NamedType(
-            decl.name, substitution.substituteType(decl.type),
+            decl.name!, substitution.substituteType(decl.type),
             isRequired: decl.isRequired))
         .toList(growable: false);
     named.sort();
@@ -3085,23 +3469,42 @@
         requiredParameterCount: requiredParameterCount);
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitFunctionNode(this);
 
-  visitChildren(Visitor v) {
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
+      v.visitFunctionNode(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(typeParameters, v);
     visitList(positionalParameters, v);
     visitList(namedParameters, v);
-    returnType?.accept(v);
+    returnType.accept(v);
     body?.accept(v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(typeParameters, v, this);
-    transformList(positionalParameters, v, this);
-    transformList(namedParameters, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(typeParameters, this);
+    v.transformList(positionalParameters, this);
+    v.transformList(namedParameters, this);
     returnType = v.visitDartType(returnType);
     if (body != null) {
-      body = body.accept<TreeNode>(v);
+      body = v.transform(body!);
+      body?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformTypeParameterList(typeParameters, this);
+    v.transformVariableDeclarationList(positionalParameters, this);
+    v.transformVariableDeclarationList(namedParameters, this);
+    returnType = v.visitDartType(returnType, cannotRemoveSentinel);
+    if (body != null) {
+      body = v.transformOrRemoveStatement(body!);
       body?.parent = this;
     }
   }
@@ -3206,8 +3609,7 @@
     DartType type = getStaticType(context);
     while (type is TypeParameterType) {
       TypeParameterType typeParameterType = type;
-      type =
-          typeParameterType.promotedBound ?? typeParameterType.parameter.bound;
+      type = typeParameterType.bound;
     }
     if (type is NullType) {
       return context.typeEnvironment.coreTypes
@@ -3217,7 +3619,7 @@
           .bottomInterfaceType(superclass, type.nullability);
     }
     if (type is InterfaceType) {
-      List<DartType> upcastTypeArguments = context.typeEnvironment
+      List<DartType>? upcastTypeArguments = context.typeEnvironment
           .getTypeArgumentsAsInstanceOf(type, superclass);
       if (upcastTypeArguments != null) {
         return new InterfaceType(
@@ -3257,18 +3659,20 @@
         .rawType(superclass, context.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg);
 
   int get precedence => astToText.Precedence.of(this);
 
+  @override
   String toText(AstTextStrategy strategy) {
     AstPrinter printer = new AstPrinter(strategy);
     printer.writeExpression(this);
     return printer.getText();
   }
-
-  void toTextInternal(AstPrinter printer);
 }
 
 /// An expression containing compile-time errors.
@@ -3304,6 +3708,9 @@
   void transformChildren(Transformer v) {}
 
   @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
+
+  @override
   String toString() {
     return "InvalidExpression(${toStringInternal()})";
   }
@@ -3319,10 +3726,13 @@
 /// Read a local variable, a local function, or a function parameter.
 class VariableGet extends Expression {
   VariableDeclaration variable;
-  DartType promotedType; // Null if not promoted.
+  DartType? promotedType; // Null if not promoted.
 
-  VariableGet(this.variable, [this.promotedType]) : assert(variable != null);
+  VariableGet(this.variable, [this.promotedType])
+      // ignore: unnecessary_null_comparison
+      : assert(variable != null);
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -3331,17 +3741,34 @@
     return promotedType ?? variable.type;
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitVariableGet(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitVariableGet(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     promotedType?.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     if (promotedType != null) {
-      promotedType = v.visitDartType(promotedType);
+      promotedType = v.visitDartType(promotedType!);
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (promotedType != null) {
+      DartType newPromotedType = v.visitDartType(promotedType!, dummyDartType);
+      if (identical(newPromotedType, dummyDartType)) {
+        promotedType = null;
+      } else {
+        promotedType = newPromotedType;
+      }
     }
   }
 
@@ -3355,7 +3782,7 @@
     printer.write(printer.getVariableName(variable));
     if (promotedType != null) {
       printer.write('{');
-      printer.writeType(promotedType);
+      printer.writeType(promotedType!);
       printer.write('}');
     }
   }
@@ -3368,10 +3795,13 @@
   VariableDeclaration variable;
   Expression value;
 
-  VariableSet(this.variable, this.value) : assert(variable != null) {
-    value?.parent = this;
+  VariableSet(this.variable, this.value)
+      // ignore: unnecessary_null_comparison
+      : assert(variable != null) {
+    value.parent = this;
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -3379,18 +3809,33 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       value.getStaticType(context);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitVariableSet(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitVariableSet(this, arg);
 
-  visitChildren(Visitor v) {
-    value?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    value.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (value != null) {
-      value = value.accept<TreeNode>(v);
-      value?.parent = this;
+      value = v.transform(value);
+      value.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (value != null) {
+      value = v.transform(value);
+      value.parent = this;
     }
   }
 
@@ -3440,10 +3885,13 @@
   Name name;
 
   DynamicGet(this.kind, this.receiver, this.name) {
-    receiver?.parent = this;
+    receiver.parent = this;
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicGet(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitDynamicGet(this, arg);
 
@@ -3458,20 +3906,29 @@
       case DynamicAccessKind.Unresolved:
         return const InvalidType();
     }
-    return const DynamicType();
   }
 
   @override
   void visitChildren(Visitor v) {
-    receiver?.accept(v);
-    name?.accept(v);
+    receiver.accept(v);
+    name.accept(v);
   }
 
   @override
   void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
   }
 
@@ -3514,41 +3971,59 @@
   Reference interfaceTargetReference;
 
   InstanceGet(InstanceAccessKind kind, Expression receiver, Name name,
-      {Member interfaceTarget, DartType resultType})
+      {required Member interfaceTarget, required DartType resultType})
       : this.byReference(kind, receiver, name,
-            interfaceTargetReference: getMemberReferenceGetter(interfaceTarget),
+            interfaceTargetReference:
+                getNonNullableMemberReferenceGetter(interfaceTarget),
             resultType: resultType);
 
   InstanceGet.byReference(this.kind, this.receiver, this.name,
-      {this.interfaceTargetReference, this.resultType})
+      {required this.interfaceTargetReference, required this.resultType})
+      // ignore: unnecessary_null_comparison
       : assert(interfaceTargetReference != null),
+        // ignore: unnecessary_null_comparison
         assert(resultType != null) {
-    receiver?.parent = this;
+    receiver.parent = this;
   }
 
-  Member get interfaceTarget => interfaceTargetReference?.asMember;
+  Member get interfaceTarget => interfaceTargetReference.asMember;
 
   void set interfaceTarget(Member member) {
-    interfaceTargetReference = getMemberReferenceSetter(member);
+    interfaceTargetReference = getNonNullableMemberReferenceSetter(member);
   }
 
   @override
   DartType getStaticTypeInternal(StaticTypeContext context) => resultType;
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceGet(this);
+
+  @override
   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);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
+    interfaceTarget.acceptReference(v);
+    name.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
   }
 
@@ -3572,24 +4047,40 @@
   Expression receiver;
 
   FunctionTearOff(this.receiver) {
-    receiver?.parent = this;
+    receiver.parent = this;
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       receiver.getStaticType(context);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionTearOff(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitFunctionTearOff(this, arg);
 
-  visitChildren(Visitor v) {
-    receiver?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
   }
 
@@ -3631,39 +4122,55 @@
   Reference interfaceTargetReference;
 
   InstanceTearOff(InstanceAccessKind kind, Expression receiver, Name name,
-      {Procedure interfaceTarget, DartType resultType})
+      {required Procedure interfaceTarget, required DartType resultType})
       : this.byReference(kind, receiver, name,
-            interfaceTargetReference: getMemberReferenceGetter(interfaceTarget),
+            interfaceTargetReference:
+                getNonNullableMemberReferenceGetter(interfaceTarget),
             resultType: resultType);
 
   InstanceTearOff.byReference(this.kind, this.receiver, this.name,
-      {this.interfaceTargetReference, this.resultType}) {
-    receiver?.parent = this;
+      {required this.interfaceTargetReference, required this.resultType}) {
+    receiver.parent = this;
   }
 
-  Procedure get interfaceTarget => interfaceTargetReference?.asMember;
+  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;
 
-  void set interfaceTarget(Member member) {
-    interfaceTargetReference = getMemberReferenceSetter(member);
+  void set interfaceTarget(Procedure procedure) {
+    interfaceTargetReference = getNonNullableMemberReferenceSetter(procedure);
   }
 
   @override
   DartType getStaticTypeInternal(StaticTypeContext context) => resultType;
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceTearOff(this);
+
+  @override
   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);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
+    interfaceTarget.acceptReference(v);
+    name.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
   }
 
@@ -3688,27 +4195,28 @@
   Expression receiver;
   Name name;
 
-  Reference interfaceTargetReference;
+  Reference? interfaceTargetReference;
 
-  PropertyGet(Expression receiver, Name name, [Member interfaceTarget])
+  PropertyGet(Expression receiver, Name name, [Member? interfaceTarget])
       : this.byReference(
             receiver, name, getMemberReferenceGetter(interfaceTarget));
 
   PropertyGet.byReference(
       this.receiver, this.name, this.interfaceTargetReference) {
-    receiver?.parent = this;
+    receiver.parent = this;
   }
 
-  Member get interfaceTarget => interfaceTargetReference?.asMember;
+  Member? get interfaceTarget => interfaceTargetReference?.asMember;
 
-  void set interfaceTarget(Member member) {
+  void set interfaceTarget(Member? member) {
     interfaceTargetReference = getMemberReferenceGetter(member);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
-    Member interfaceTarget = this.interfaceTarget;
+    Member? interfaceTarget = this.interfaceTarget;
     if (interfaceTarget != null) {
-      Class superclass = interfaceTarget.enclosingClass;
+      Class superclass = interfaceTarget.enclosingClass!;
       InterfaceType receiverType =
           receiver.getStaticTypeAsInstanceOf(superclass, context);
       return Substitution.fromInterfaceType(receiverType)
@@ -3724,20 +4232,35 @@
     return const DynamicType();
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitPropertyGet(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitPropertyGet(this, arg);
 
-  visitChildren(Visitor v) {
-    receiver?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
     interfaceTarget?.acceptReference(v);
-    name?.accept(v);
+    name.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
   }
 
@@ -3762,31 +4285,53 @@
   Expression value;
 
   DynamicSet(this.kind, this.receiver, this.name, this.value) {
-    receiver?.parent = this;
-    value?.parent = this;
+    receiver.parent = this;
+    value.parent = this;
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       value.getStaticType(context);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicSet(this);
+
+  @override
   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);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
+    name.accept(v);
+    value.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (value != null) {
-      value = value.accept<TreeNode>(v);
-      value?.parent = this;
+      value = v.transform(value);
+      value.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (value != null) {
+      value = v.transform(value);
+      value.parent = this;
     }
   }
 
@@ -3818,46 +4363,69 @@
 
   InstanceSet(
       InstanceAccessKind kind, Expression receiver, Name name, Expression value,
-      {Member interfaceTarget})
+      {required Member interfaceTarget})
       : this.byReference(kind, receiver, name, value,
             interfaceTargetReference:
-                getMemberReferenceSetter(interfaceTarget));
+                getNonNullableMemberReferenceSetter(interfaceTarget));
 
   InstanceSet.byReference(this.kind, this.receiver, this.name, this.value,
-      {this.interfaceTargetReference})
+      {required this.interfaceTargetReference})
+      // ignore: unnecessary_null_comparison
       : assert(interfaceTargetReference != null) {
-    receiver?.parent = this;
-    value?.parent = this;
+    receiver.parent = this;
+    value.parent = this;
   }
 
-  Member get interfaceTarget => interfaceTargetReference?.asMember;
+  Member get interfaceTarget => interfaceTargetReference.asMember;
 
   void set interfaceTarget(Member member) {
-    interfaceTargetReference = getMemberReferenceSetter(member);
+    interfaceTargetReference = getNonNullableMemberReferenceSetter(member);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       value.getStaticType(context);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceSet(this);
+
+  @override
   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);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
+    interfaceTarget.acceptReference(v);
+    name.accept(v);
+    value.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (value != null) {
-      value = value.accept<TreeNode>(v);
-      value?.parent = this;
+      value = v.transform(value);
+      value.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (value != null) {
+      value = v.transform(value);
+      value.parent = this;
     }
   }
 
@@ -3887,47 +4455,69 @@
   Name name;
   Expression value;
 
-  Reference interfaceTargetReference;
+  Reference? interfaceTargetReference;
 
   PropertySet(Expression receiver, Name name, Expression value,
-      [Member interfaceTarget])
+      [Member? interfaceTarget])
       : this.byReference(
             receiver, name, value, getMemberReferenceSetter(interfaceTarget));
 
   PropertySet.byReference(
       this.receiver, this.name, this.value, this.interfaceTargetReference) {
-    receiver?.parent = this;
-    value?.parent = this;
+    receiver.parent = this;
+    value.parent = this;
   }
 
-  Member get interfaceTarget => interfaceTargetReference?.asMember;
+  Member? get interfaceTarget => interfaceTargetReference?.asMember;
 
-  void set interfaceTarget(Member member) {
+  void set interfaceTarget(Member? member) {
     interfaceTargetReference = getMemberReferenceSetter(member);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       value.getStaticType(context);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitPropertySet(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitPropertySet(this, arg);
 
-  visitChildren(Visitor v) {
-    receiver?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
     interfaceTarget?.acceptReference(v);
-    name?.accept(v);
-    value?.accept(v);
+    name.accept(v);
+    value.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (value != null) {
-      value = value.accept<TreeNode>(v);
-      value?.parent = this;
+      value = v.transform(value);
+      value.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (value != null) {
+      value = v.transform(value);
+      value.parent = this;
     }
   }
 
@@ -3953,46 +4543,56 @@
 class SuperPropertyGet extends Expression {
   Name name;
 
-  Reference interfaceTargetReference;
+  Reference? interfaceTargetReference;
 
-  SuperPropertyGet(Name name, [Member interfaceTarget])
+  SuperPropertyGet(Name name, [Member? interfaceTarget])
       : this.byReference(name, getMemberReferenceGetter(interfaceTarget));
 
   SuperPropertyGet.byReference(this.name, this.interfaceTargetReference);
 
-  Member get interfaceTarget => interfaceTargetReference?.asMember;
+  Member? get interfaceTarget => interfaceTargetReference?.asMember;
 
-  void set interfaceTarget(Member member) {
+  void set interfaceTarget(Member? member) {
     interfaceTargetReference = getMemberReferenceGetter(member);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
+    Member? interfaceTarget = this.interfaceTarget;
     if (interfaceTarget == null) {
       // TODO(johnniwinther): SuperPropertyGet without a target should be
       // replaced by invalid expressions.
       return const DynamicType();
     }
-    Class declaringClass = interfaceTarget.enclosingClass;
+    Class declaringClass = interfaceTarget.enclosingClass!;
     if (declaringClass.typeParameters.isEmpty) {
       return interfaceTarget.getterType;
     }
-    List<DartType> receiverArguments = context.typeEnvironment
-        .getTypeArgumentsAsInstanceOf(context.thisType, declaringClass);
+    List<DartType>? receiverArguments = context.typeEnvironment
+        .getTypeArgumentsAsInstanceOf(context.thisType!, declaringClass);
     return Substitution.fromPairs(
-            declaringClass.typeParameters, receiverArguments)
+            declaringClass.typeParameters, receiverArguments!)
         .substituteType(interfaceTarget.getterType);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertyGet(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitSuperPropertyGet(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     interfaceTarget?.acceptReference(v);
-    name?.accept(v);
+    name.accept(v);
   }
 
-  transformChildren(Transformer v) {}
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -4015,7 +4615,7 @@
   Name name;
   Expression value;
 
-  Reference interfaceTargetReference;
+  Reference? interfaceTargetReference;
 
   SuperPropertySet(Name name, Expression value, Member interfaceTarget)
       : this.byReference(
@@ -4023,32 +4623,48 @@
 
   SuperPropertySet.byReference(
       this.name, this.value, this.interfaceTargetReference) {
-    value?.parent = this;
+    value.parent = this;
   }
 
-  Member get interfaceTarget => interfaceTargetReference?.asMember;
+  Member? get interfaceTarget => interfaceTargetReference?.asMember;
 
-  void set interfaceTarget(Member member) {
+  void set interfaceTarget(Member? member) {
     interfaceTargetReference = getMemberReferenceSetter(member);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       value.getStaticType(context);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertySet(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitSuperPropertySet(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     interfaceTarget?.acceptReference(v);
-    name?.accept(v);
-    value?.accept(v);
+    name.accept(v);
+    value.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (value != null) {
-      value = value.accept<TreeNode>(v);
-      value?.parent = this;
+      value = v.transform(value);
+      value.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (value != null) {
+      value = v.transform(value);
+      value.parent = this;
     }
   }
 
@@ -4071,28 +4687,38 @@
   /// A static field, getter, or method (for tear-off).
   Reference targetReference;
 
-  StaticGet(Member target) : this.byReference(getMemberReferenceGetter(target));
+  StaticGet(Member target)
+      : this.byReference(getNonNullableMemberReferenceGetter(target));
 
   StaticGet.byReference(this.targetReference);
 
-  Member get target => targetReference?.asMember;
+  Member get target => targetReference.asMember;
 
   void set target(Member target) {
-    targetReference = getMemberReferenceGetter(target);
+    targetReference = getNonNullableMemberReferenceGetter(target);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       target.getterType;
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitStaticGet(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitStaticGet(this, arg);
 
-  visitChildren(Visitor v) {
-    target?.acceptReference(v);
+  @override
+  void visitChildren(Visitor v) {
+    target.acceptReference(v);
   }
 
-  transformChildren(Transformer v) {}
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -4110,28 +4736,37 @@
   Reference targetReference;
 
   StaticTearOff(Procedure target)
-      : this.byReference(getMemberReferenceGetter(target));
+      : this.byReference(getNonNullableMemberReferenceGetter(target));
 
   StaticTearOff.byReference(this.targetReference);
 
-  Procedure get target => targetReference?.asProcedure;
+  Procedure get target => targetReference.asProcedure;
 
   void set target(Procedure target) {
-    targetReference = getMemberReferenceGetter(target);
+    targetReference = getNonNullableMemberReferenceGetter(target);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       target.getterType;
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitStaticTearOff(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitStaticTearOff(this, arg);
 
-  visitChildren(Visitor v) {
-    target?.acceptReference(v);
+  @override
+  void visitChildren(Visitor v) {
+    target.acceptReference(v);
   }
 
-  transformChildren(Transformer v) {}
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -4153,34 +4788,50 @@
   Expression value;
 
   StaticSet(Member target, Expression value)
-      : this.byReference(getMemberReferenceSetter(target), value);
+      : this.byReference(getNonNullableMemberReferenceSetter(target), value);
 
   StaticSet.byReference(this.targetReference, this.value) {
-    value?.parent = this;
+    value.parent = this;
   }
 
-  Member get target => targetReference?.asMember;
+  Member get target => targetReference.asMember;
 
   void set target(Member target) {
-    targetReference = getMemberReferenceSetter(target);
+    targetReference = getNonNullableMemberReferenceSetter(target);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       value.getStaticType(context);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitStaticSet(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitStaticSet(this, arg);
 
-  visitChildren(Visitor v) {
-    target?.acceptReference(v);
-    value?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    target.acceptReference(v);
+    value.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (value != null) {
-      value = value.accept<TreeNode>(v);
-      value?.parent = this;
+      value = v.transform(value);
+      value.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (value != null) {
+      value = v.transform(value);
+      value.parent = this;
     }
   }
 
@@ -4205,7 +4856,7 @@
   List<NamedExpression> named;
 
   Arguments(this.positional,
-      {List<DartType> types, List<NamedExpression> named})
+      {List<DartType>? types, List<NamedExpression>? named})
       : this.types = types ?? <DartType>[],
         this.named = named ?? <NamedExpression>[] {
     setParents(this.positional, this);
@@ -4223,7 +4874,7 @@
             .map<Expression>((p) => new VariableGet(p))
             .toList(),
         named: function.namedParameters
-            .map((p) => new NamedExpression(p.name, new VariableGet(p)))
+            .map((p) => new NamedExpression(p.name!, new VariableGet(p)))
             .toList(),
         types: function.typeParameters
             .map<DartType>((p) =>
@@ -4232,18 +4883,31 @@
             .toList());
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitArguments(this);
 
-  visitChildren(Visitor v) {
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitArguments(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(types, v);
     visitList(positional, v);
     visitList(named, v);
   }
 
-  transformChildren(Transformer v) {
-    transformTypeList(types, v);
-    transformList(positional, v, this);
-    transformList(named, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformDartTypeList(types);
+    v.transformList(positional, this);
+    v.transformList(named, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformDartTypeList(types);
+    v.transformExpressionList(positional, this);
+    v.transformNamedExpressionList(named, this);
   }
 
   @override
@@ -4251,12 +4915,14 @@
     return "Arguments(${toStringInternal()})";
   }
 
+  @override
   String toText(AstTextStrategy strategy) {
     AstPrinter printer = new AstPrinter(strategy);
     printer.writeArguments(this);
     return printer.getText();
   }
 
+  @override
   void toTextInternal(AstPrinter printer, {bool includeTypeArguments: true}) {
     if (includeTypeArguments) {
       printer.writeTypeArguments(types);
@@ -4289,19 +4955,36 @@
   Expression value;
 
   NamedExpression(this.name, this.value) {
-    value?.parent = this;
+    value.parent = this;
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitNamedExpression(this);
 
-  visitChildren(Visitor v) {
-    value?.accept(v);
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
+      v.visitNamedExpression(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
+    value.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (value != null) {
-      value = value.accept<TreeNode>(v);
-      value?.parent = this;
+      value = v.transform(value);
+      value.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (value != null) {
+      value = v.transform(value);
+      value.parent = this;
     }
   }
 
@@ -4310,12 +4993,14 @@
     return "NamedExpression(${toStringInternal()})";
   }
 
+  @override
   String toText(AstTextStrategy strategy) {
     AstPrinter printer = new AstPrinter(strategy);
     toTextInternal(printer);
     return printer.getText();
   }
 
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.write(name);
     printer.write(': ');
@@ -4330,20 +5015,22 @@
   void set arguments(Arguments value);
 
   /// Name of the invoked method.
-  ///
-  /// May be `null` if the target is a synthetic static member without a name.
   Name get name;
 }
 
 class DynamicInvocation extends InvocationExpression {
   final DynamicAccessKind kind;
   Expression receiver;
+
+  @override
   Name name;
+
+  @override
   Arguments arguments;
 
   DynamicInvocation(this.kind, this.receiver, this.name, this.arguments) {
-    receiver?.parent = this;
-    arguments?.parent = this;
+    receiver.parent = this;
+    arguments.parent = this;
   }
 
   @override
@@ -4357,27 +5044,47 @@
       case DynamicAccessKind.Unresolved:
         return const InvalidType();
     }
-    return const DynamicType();
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicInvocation(this);
+
+  @override
   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);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
+    name.accept(v);
+    arguments.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
-      arguments?.parent = this;
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
     }
   }
 
@@ -4458,8 +5165,13 @@
 
   final InstanceAccessKind kind;
   Expression receiver;
+
+  @override
   Name name;
+
+  @override
   Arguments arguments;
+
   int flags = 0;
 
   /// The static type of the invocation.
@@ -4481,25 +5193,29 @@
   Reference interfaceTargetReference;
 
   InstanceInvocation(InstanceAccessKind kind, Expression receiver, Name name,
-      Arguments arguments, {Member interfaceTarget, FunctionType functionType})
+      Arguments arguments,
+      {required Member interfaceTarget, required FunctionType functionType})
       : this.byReference(kind, receiver, name, arguments,
-            interfaceTargetReference: getMemberReferenceGetter(interfaceTarget),
+            interfaceTargetReference:
+                getNonNullableMemberReferenceGetter(interfaceTarget),
             functionType: functionType);
 
   InstanceInvocation.byReference(
       this.kind, this.receiver, this.name, this.arguments,
-      {this.interfaceTargetReference, this.functionType})
+      {required this.interfaceTargetReference, required this.functionType})
+      // ignore: unnecessary_null_comparison
       : assert(interfaceTargetReference != null),
+        // ignore: unnecessary_null_comparison
         assert(functionType != null),
         assert(functionType.typeParameters.isEmpty) {
-    receiver?.parent = this;
-    arguments?.parent = this;
+    receiver.parent = this;
+    arguments.parent = this;
   }
 
-  Member get interfaceTarget => interfaceTargetReference?.asMember;
+  Member get interfaceTarget => interfaceTargetReference.asMember;
 
   void set interfaceTarget(Member target) {
-    interfaceTargetReference = getMemberReferenceGetter(target);
+    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
   }
 
   /// If `true`, this call is known to be safe wrt. parameter covariance checks.
@@ -4537,28 +5253,50 @@
     flags = value ? (flags | FlagBoundsSafe) : (flags & ~FlagBoundsSafe);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       functionType.returnType;
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceInvocation(this);
+
+  @override
   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);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
+    interfaceTarget.acceptReference(v);
+    name.accept(v);
+    arguments.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
-      arguments?.parent = this;
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
     }
   }
 
@@ -4629,6 +5367,7 @@
 
   Expression receiver;
 
+  @override
   Arguments arguments;
 
   /// The static type of the invocation.
@@ -4646,37 +5385,60 @@
   ///      local(0); // The function type is `int Function(int)`.
   ///    }
   ///
-  FunctionType functionType;
+  FunctionType? functionType;
 
   FunctionInvocation(this.kind, this.receiver, this.arguments,
-      {this.functionType}) {
-    receiver?.parent = this;
-    arguments?.parent = this;
+      {required this.functionType}) {
+    receiver.parent = this;
+    arguments.parent = this;
   }
 
+  @override
   Name get name => Name.callName;
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       functionType?.returnType ?? const DynamicType();
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionInvocation(this);
+
+  @override
   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);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
+    name.accept(v);
+    arguments.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
-      arguments?.parent = this;
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
     }
   }
 
@@ -4697,6 +5459,8 @@
 class LocalFunctionInvocation extends InvocationExpression {
   /// The variable declaration for the function declaration.
   VariableDeclaration variable;
+
+  @override
   Arguments arguments;
 
   /// The static type of the invocation.
@@ -4713,29 +5477,47 @@
   ///
   FunctionType functionType;
 
-  LocalFunctionInvocation(this.variable, this.arguments, {this.functionType})
+  LocalFunctionInvocation(this.variable, this.arguments,
+      {required this.functionType})
+      // ignore: unnecessary_null_comparison
       : assert(functionType != null) {
-    arguments?.parent = this;
+    arguments.parent = this;
   }
 
+  @override
   Name get name => Name.callName;
 
   @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       functionType.returnType;
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitLocalFunctionInvocation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitLocalFunctionInvocation(this, arg);
 
-  visitChildren(Visitor v) {
-    arguments?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    arguments.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
-      arguments?.parent = this;
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
     }
   }
 
@@ -4763,26 +5545,43 @@
   /// test.
   final bool isNot;
 
-  EqualsNull(this.expression, {this.isNot}) : assert(isNot != null) {
-    expression?.parent = this;
+  EqualsNull(this.expression, {required this.isNot})
+      // ignore: unnecessary_null_comparison
+      : assert(isNot != null) {
+    expression.parent = this;
   }
 
   @override
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitEqualsNull(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitEqualsNull(this, arg);
 
-  visitChildren(Visitor v) {
-    expression?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    expression.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
-      expression?.parent = this;
+      expression = v.transform(expression);
+      expression.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (expression != null) {
+      expression = v.transform(expression);
+      expression.parent = this;
     }
   }
 
@@ -4831,49 +5630,75 @@
   Reference interfaceTargetReference;
 
   EqualsCall(Expression left, Expression right,
-      {bool isNot, FunctionType functionType, Procedure interfaceTarget})
+      {required bool isNot,
+      required FunctionType functionType,
+      required Procedure interfaceTarget})
       : this.byReference(left, right,
             isNot: isNot,
             functionType: functionType,
             interfaceTargetReference:
-                getMemberReferenceGetter(interfaceTarget));
+                getNonNullableMemberReferenceGetter(interfaceTarget));
 
   EqualsCall.byReference(this.left, this.right,
-      {this.isNot, this.functionType, this.interfaceTargetReference})
+      {required this.isNot,
+      required this.functionType,
+      required this.interfaceTargetReference})
+      // ignore: unnecessary_null_comparison
       : assert(isNot != null) {
-    left?.parent = this;
-    right?.parent = this;
+    left.parent = this;
+    right.parent = this;
   }
 
-  Procedure get interfaceTarget => interfaceTargetReference?.asProcedure;
+  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;
 
   void set interfaceTarget(Procedure target) {
-    interfaceTargetReference = getMemberReferenceGetter(target);
+    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
-    return functionType?.returnType ??
-        context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
+    return functionType.returnType;
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitEqualsCall(this);
+
+  @override
   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);
+  @override
+  void visitChildren(Visitor v) {
+    left.accept(v);
+    interfaceTarget.acceptReference(v);
+    right.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (left != null) {
-      left = left.accept<TreeNode>(v);
-      left?.parent = this;
+      left = v.transform(left);
+      left.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (right != null) {
-      right = right.accept<TreeNode>(v);
-      right?.parent = this;
+      right = v.transform(right);
+      right.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (left != null) {
+      left = v.transform(left);
+      left.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (right != null) {
+      right = v.transform(right);
+      right.parent = this;
     }
   }
 
@@ -4902,14 +5727,19 @@
   static const int FlagBoundsSafe = 1 << 1;
 
   Expression receiver;
+
+  @override
   Name name;
+
+  @override
   Arguments arguments;
+
   int flags = 0;
 
-  Reference interfaceTargetReference;
+  Reference? interfaceTargetReference;
 
   MethodInvocation(Expression receiver, Name name, Arguments arguments,
-      [Member interfaceTarget])
+      [Member? interfaceTarget])
       : this.byReference(
             receiver,
             name,
@@ -4919,13 +5749,13 @@
 
   MethodInvocation.byReference(
       this.receiver, this.name, this.arguments, this.interfaceTargetReference) {
-    receiver?.parent = this;
-    arguments?.parent = this;
+    receiver.parent = this;
+    arguments.parent = this;
   }
 
-  Member get interfaceTarget => interfaceTargetReference?.asMember;
+  Member? get interfaceTarget => interfaceTargetReference?.asMember;
 
-  void set interfaceTarget(Member target) {
+  void set interfaceTarget(Member? target) {
     // An invocation doesn't refer to the setter.
     interfaceTargetReference = getMemberReferenceGetter(target);
   }
@@ -4965,8 +5795,9 @@
     flags = value ? (flags | FlagBoundsSafe) : (flags & ~FlagBoundsSafe);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
-    Member interfaceTarget = this.interfaceTarget;
+    Member? interfaceTarget = this.interfaceTarget;
     if (interfaceTarget != null) {
       if (interfaceTarget is Procedure &&
           context.typeEnvironment
@@ -4975,8 +5806,8 @@
             receiver.getStaticType(context),
             arguments.positional[0].getStaticType(context));
       }
-      Class superclass = interfaceTarget.enclosingClass;
-      DartType receiverType =
+      Class superclass = interfaceTarget.enclosingClass!;
+      InterfaceType receiverType =
           receiver.getStaticTypeAsInstanceOf(superclass, context);
       DartType getterType = Substitution.fromInterfaceType(receiverType)
           .substituteType(interfaceTarget.getterType);
@@ -4993,7 +5824,7 @@
               getterType.typeParameters,
               getterType.typeParameters
                   .map((TypeParameter typeParameter) =>
-                      typeParameter.defaultType)
+                      typeParameter.defaultType!)
                   .toList());
         }
         return substitution.substituteType(getterType.returnType);
@@ -5004,7 +5835,7 @@
       // TODO(johnniwinther): Remove this when the front end performs the
       // correct replacement.
       if (getterType is InterfaceType) {
-        Member member = context.typeEnvironment
+        Member? member = context.typeEnvironment
             .getInterfaceMember(getterType.classNode, new Name('call'));
         if (member != null) {
           DartType callType = member.getterType;
@@ -5034,25 +5865,46 @@
     return const DynamicType();
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitMethodInvocation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitMethodInvocation(this, arg);
 
-  visitChildren(Visitor v) {
-    receiver?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    receiver.accept(v);
     interfaceTarget?.acceptReference(v);
-    name?.accept(v);
-    arguments?.accept(v);
+    name.accept(v);
+    arguments.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (receiver != null) {
-      receiver = receiver.accept<TreeNode>(v);
-      receiver?.parent = this;
+      receiver = v.transform(receiver);
+      receiver.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
-      arguments?.parent = this;
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (receiver != null) {
+      receiver = v.transform(receiver);
+      receiver.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
     }
   }
 
@@ -5075,13 +5927,16 @@
 ///
 /// The provided arguments might not match the parameters of the target.
 class SuperMethodInvocation extends InvocationExpression {
+  @override
   Name name;
+
+  @override
   Arguments arguments;
 
-  Reference interfaceTargetReference;
+  Reference? interfaceTargetReference;
 
   SuperMethodInvocation(Name name, Arguments arguments,
-      [Procedure interfaceTarget])
+      [Procedure? interfaceTarget])
       : this.byReference(
             name,
             arguments,
@@ -5090,43 +5945,60 @@
 
   SuperMethodInvocation.byReference(
       this.name, this.arguments, this.interfaceTargetReference) {
-    arguments?.parent = this;
+    arguments.parent = this;
   }
 
-  Procedure get interfaceTarget => interfaceTargetReference?.asProcedure;
+  Procedure? get interfaceTarget => interfaceTargetReference?.asProcedure;
 
-  void set interfaceTarget(Procedure target) {
+  void set interfaceTarget(Procedure? target) {
     // An invocation doesn't refer to the setter.
     interfaceTargetReference = getMemberReferenceGetter(target);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
+    Procedure? interfaceTarget = this.interfaceTarget;
     if (interfaceTarget == null) return const DynamicType();
-    Class superclass = interfaceTarget.enclosingClass;
-    List<DartType> receiverTypeArguments = context.typeEnvironment
-        .getTypeArgumentsAsInstanceOf(context.thisType, superclass);
-    DartType returnType =
-        Substitution.fromPairs(superclass.typeParameters, receiverTypeArguments)
-            .substituteType(interfaceTarget.function.returnType);
+    Class superclass = interfaceTarget.enclosingClass!;
+    List<DartType>? receiverTypeArguments = context.typeEnvironment
+        .getTypeArgumentsAsInstanceOf(context.thisType!, superclass);
+    DartType returnType = Substitution.fromPairs(
+            superclass.typeParameters, receiverTypeArguments!)
+        .substituteType(interfaceTarget.function!.returnType);
     return Substitution.fromPairs(
-            interfaceTarget.function.typeParameters, arguments.types)
+            interfaceTarget.function!.typeParameters, arguments.types)
         .substituteType(returnType);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitSuperMethodInvocation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitSuperMethodInvocation(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     interfaceTarget?.acceptReference(v);
-    name?.accept(v);
-    arguments?.accept(v);
+    name.accept(v);
+    arguments.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
-      arguments?.parent = this;
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
     }
   }
 
@@ -5149,51 +6021,70 @@
 /// The provided arguments might not match the parameters of the target.
 class StaticInvocation extends InvocationExpression {
   Reference targetReference;
+
+  @override
   Arguments arguments;
 
   /// True if this is a constant call to an external constant factory.
   bool isConst;
 
-  Name get name => target?.name;
+  @override
+  Name get name => target.name!;
 
   StaticInvocation(Procedure target, Arguments arguments, {bool isConst: false})
       : this.byReference(
             // An invocation doesn't refer to the setter.
-            getMemberReferenceGetter(target),
+            getNonNullableMemberReferenceGetter(target),
             arguments,
             isConst: isConst);
 
   StaticInvocation.byReference(this.targetReference, this.arguments,
       {this.isConst: false}) {
-    arguments?.parent = this;
+    arguments.parent = this;
   }
 
-  Procedure get target => targetReference?.asProcedure;
+  Procedure get target => targetReference.asProcedure;
 
   void set target(Procedure target) {
     // An invocation doesn't refer to the setter.
-    targetReference = getMemberReferenceGetter(target);
+    targetReference = getNonNullableMemberReferenceGetter(target);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
     return Substitution.fromPairs(
-            target.function.typeParameters, arguments.types)
-        .substituteType(target.function.returnType);
+            target.function!.typeParameters, arguments.types)
+        .substituteType(target.function!.returnType);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitStaticInvocation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitStaticInvocation(this, arg);
 
-  visitChildren(Visitor v) {
-    target?.acceptReference(v);
-    arguments?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    target.acceptReference(v);
+    arguments.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
-      arguments?.parent = this;
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
     }
   }
 
@@ -5218,58 +6109,78 @@
 // generic functions.
 class ConstructorInvocation extends InvocationExpression {
   Reference targetReference;
+
+  @override
   Arguments arguments;
+
   bool isConst;
 
-  Name get name => target?.name;
+  @override
+  Name get name => target.name!;
 
   ConstructorInvocation(Constructor target, Arguments arguments,
       {bool isConst: false})
       : this.byReference(
             // A constructor doesn't refer to the setter.
-            getMemberReferenceGetter(target),
+            getNonNullableMemberReferenceGetter(target),
             arguments,
             isConst: isConst);
 
   ConstructorInvocation.byReference(this.targetReference, this.arguments,
       {this.isConst: false}) {
-    arguments?.parent = this;
+    arguments.parent = this;
   }
 
-  Constructor get target => targetReference?.asConstructor;
+  Constructor get target => targetReference.asConstructor;
 
   void set target(Constructor target) {
     // A constructor doesn't refer to the setter.
-    targetReference = getMemberReferenceGetter(target);
+    targetReference = getNonNullableMemberReferenceGetter(target);
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
     return arguments.types.isEmpty
         ? context.typeEnvironment.coreTypes
-            .rawType(target.enclosingClass, context.nonNullable)
+            .rawType(target.enclosingClass!, context.nonNullable)
         : new InterfaceType(
-            target.enclosingClass, context.nonNullable, arguments.types);
+            target.enclosingClass!, context.nonNullable, arguments.types);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitConstructorInvocation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitConstructorInvocation(this, arg);
 
-  visitChildren(Visitor v) {
-    target?.acceptReference(v);
-    arguments?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    target.acceptReference(v);
+    arguments.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (arguments != null) {
-      arguments = arguments.accept<TreeNode>(v);
-      arguments?.parent = this;
+      arguments = v.transform(arguments);
+      arguments.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (arguments != null) {
+      arguments = v.transform(arguments);
+      arguments.parent = this;
     }
   }
 
   // TODO(dmitryas): Change the getter into a method that accepts a CoreTypes.
   InterfaceType get constructedType {
-    Class enclosingClass = target.enclosingClass;
+    Class enclosingClass = target.enclosingClass!;
     // TODO(dmitryas): Get raw type from a CoreTypes object if arguments is
     // empty.
     return arguments.types.isEmpty
@@ -5291,11 +6202,11 @@
     } else {
       printer.write('new ');
     }
-    printer.writeClassName(target.enclosingClass.reference);
+    printer.writeClassName(target.enclosingClass!.reference);
     printer.writeTypeArguments(arguments.types);
-    if (target.name.text.isNotEmpty) {
+    if (target.name!.text.isNotEmpty) {
       printer.write('.');
-      printer.write(target.name.text);
+      printer.write(target.name!.text);
     }
     printer.writeArguments(arguments, includeTypeArguments: false);
   }
@@ -5307,30 +6218,47 @@
   final List<DartType> typeArguments;
 
   Instantiation(this.expression, this.typeArguments) {
-    expression?.parent = this;
+    expression.parent = this;
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
-    FunctionType type = expression.getStaticType(context);
+    FunctionType type = expression.getStaticType(context) as FunctionType;
     return Substitution.fromPairs(type.typeParameters, typeArguments)
         .substituteType(type.withoutTypeParameters);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitInstantiation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitInstantiation(this, arg);
 
-  visitChildren(Visitor v) {
-    expression?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    expression.accept(v);
     visitList(typeArguments, v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
-      expression?.parent = this;
+      expression = v.transform(expression);
+      expression.parent = this;
     }
-    transformTypeList(typeArguments, v);
+    v.transformDartTypeList(typeArguments);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (expression != null) {
+      expression = v.transform(expression);
+      expression.parent = this;
+    }
+    v.transformDartTypeList(typeArguments);
   }
 
   @override
@@ -5353,9 +6281,10 @@
   Expression operand;
 
   Not(this.operand) {
-    operand?.parent = this;
+    operand.parent = this;
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -5363,17 +6292,32 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitNot(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitNot(this, arg);
 
-  visitChildren(Visitor v) {
-    operand?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    operand.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (operand != null) {
-      operand = operand.accept<TreeNode>(v);
-      operand?.parent = this;
+      operand = v.transform(operand);
+      operand.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (operand != null) {
+      operand = v.transform(operand);
+      operand.parent = this;
     }
   }
 
@@ -5399,7 +6343,6 @@
     case LogicalExpressionOperator.OR:
       return "||";
   }
-  throw "Unhandled LogicalExpressionOperator: ${operator}";
 }
 
 /// Expression of form `x && y` or `x || y`
@@ -5409,10 +6352,11 @@
   Expression right;
 
   LogicalExpression(this.left, this.operatorEnum, this.right) {
-    left?.parent = this;
-    right?.parent = this;
+    left.parent = this;
+    right.parent = this;
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -5420,23 +6364,44 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitLogicalExpression(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitLogicalExpression(this, arg);
 
-  visitChildren(Visitor v) {
-    left?.accept(v);
-    right?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    left.accept(v);
+    right.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (left != null) {
-      left = left.accept<TreeNode>(v);
-      left?.parent = this;
+      left = v.transform(left);
+      left.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (right != null) {
-      right = right.accept<TreeNode>(v);
-      right?.parent = this;
+      right = v.transform(right);
+      right.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (left != null) {
+      left = v.transform(left);
+      left.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (right != null) {
+      right = v.transform(right);
+      right.parent = this;
     }
   }
 
@@ -5460,52 +6425,85 @@
   Expression then;
   Expression otherwise;
 
-  /// The static type of the expression. Should not be `null`.
+  /// The static type of the expression.
   DartType staticType;
 
   ConditionalExpression(
       this.condition, this.then, this.otherwise, this.staticType) {
-    condition?.parent = this;
-    then?.parent = this;
-    otherwise?.parent = this;
+    condition.parent = this;
+    then.parent = this;
+    otherwise.parent = this;
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
   @override
   DartType getStaticTypeInternal(StaticTypeContext context) => staticType;
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitConditionalExpression(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitConditionalExpression(this, arg);
 
-  visitChildren(Visitor v) {
-    condition?.accept(v);
-    then?.accept(v);
-    otherwise?.accept(v);
-    staticType?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    condition.accept(v);
+    then.accept(v);
+    otherwise.accept(v);
+    staticType.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (condition != null) {
-      condition = condition.accept<TreeNode>(v);
-      condition?.parent = this;
+      condition = v.transform(condition);
+      condition.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (then != null) {
-      then = then.accept<TreeNode>(v);
-      then?.parent = this;
+      then = v.transform(then);
+      then.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (otherwise != null) {
-      otherwise = otherwise.accept<TreeNode>(v);
-      otherwise?.parent = this;
+      otherwise = v.transform(otherwise);
+      otherwise.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (staticType != null) {
       staticType = v.visitDartType(staticType);
     }
   }
 
   @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (condition != null) {
+      condition = v.transform(condition);
+      condition.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (then != null) {
+      then = v.transform(then);
+      then.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (otherwise != null) {
+      otherwise = v.transform(otherwise);
+      otherwise.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (staticType != null) {
+      staticType = v.visitDartType(staticType, cannotRemoveSentinel);
+    }
+  }
+
+  @override
   String toString() {
     return "ConditionalExpression(${toStringInternal()})";
   }
@@ -5515,6 +6513,7 @@
     printer.writeExpression(condition,
         minimumPrecedence: astToText.Precedence.LOGICAL_OR);
     printer.write(' ?');
+    // ignore: unnecessary_null_comparison
     if (staticType != null) {
       printer.write('{');
       printer.writeType(staticType);
@@ -5541,6 +6540,7 @@
     setParents(expressions, this);
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -5548,16 +6548,26 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitStringConcatenation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitStringConcatenation(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     visitList(expressions, v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(expressions, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(expressions, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(expressions, this);
   }
 
   @override
@@ -5596,6 +6606,7 @@
     setParents(lists, this);
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -5604,18 +6615,29 @@
     return context.typeEnvironment.listType(typeArgument, context.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitListConcatenation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitListConcatenation(this, arg);
 
-  visitChildren(Visitor v) {
-    typeArgument?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    typeArgument.accept(v);
     visitList(lists, v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     typeArgument = v.visitDartType(typeArgument);
-    transformList(lists, v, this);
+    v.transformList(lists, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
+    v.transformExpressionList(lists, this);
   }
 
   @override
@@ -5654,6 +6676,7 @@
     setParents(sets, this);
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -5662,18 +6685,29 @@
     return context.typeEnvironment.setType(typeArgument, context.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitSetConcatenation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitSetConcatenation(this, arg);
 
-  visitChildren(Visitor v) {
-    typeArgument?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    typeArgument.accept(v);
     visitList(sets, v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     typeArgument = v.visitDartType(typeArgument);
-    transformList(sets, v, this);
+    v.transformList(sets, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
+    v.transformExpressionList(sets, this);
   }
 
   @override
@@ -5715,6 +6749,7 @@
     setParents(maps, this);
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -5724,20 +6759,32 @@
         .mapType(keyType, valueType, context.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitMapConcatenation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitMapConcatenation(this, arg);
 
-  visitChildren(Visitor v) {
-    keyType?.accept(v);
-    valueType?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    keyType.accept(v);
+    valueType.accept(v);
     visitList(maps, v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     keyType = v.visitDartType(keyType);
     valueType = v.visitDartType(valueType);
-    transformList(maps, v, this);
+    v.transformList(maps, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    keyType = v.visitDartType(keyType, cannotRemoveSentinel);
+    valueType = v.visitDartType(valueType, cannotRemoveSentinel);
+    v.transformExpressionList(maps, this);
   }
 
   @override
@@ -5780,6 +6827,7 @@
 
   Class get classNode => classReference.asClass;
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -5791,11 +6839,15 @@
         : new InterfaceType(classNode, context.nonNullable, typeArguments);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceCreation(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitInstanceCreation(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     classReference.asClass.acceptReference(v);
     visitList(typeArguments, v);
     for (final Reference reference in fieldValues.keys) {
@@ -5808,16 +6860,31 @@
     visitList(unusedArguments, v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     fieldValues.forEach((Reference fieldRef, Expression value) {
-      Expression transformed = value.accept<TreeNode>(v);
+      Expression transformed = v.transform(value);
+      // ignore: unnecessary_null_comparison
       if (transformed != null && !identical(value, transformed)) {
         fieldValues[fieldRef] = transformed;
         transformed.parent = this;
       }
     });
-    transformList(asserts, v, this);
-    transformList(unusedArguments, v, this);
+    v.transformList(asserts, this);
+    v.transformList(unusedArguments, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    fieldValues.forEach((Reference fieldRef, Expression value) {
+      Expression transformed = v.transform(value);
+      if (!identical(value, transformed)) {
+        fieldValues[fieldRef] = transformed;
+        transformed.parent = this;
+      }
+    });
+    v.transformList(asserts, this, dummyAssertStatement);
+    v.transformExpressionList(unusedArguments, this);
   }
 
   @override
@@ -5848,7 +6915,7 @@
       printer.writeExpression(assert_.condition);
       if (assert_.message != null) {
         printer.write(', ');
-        printer.writeExpression(assert_.message);
+        printer.writeExpression(assert_.message!);
       }
       printer.write(')');
       first = false;
@@ -5881,6 +6948,7 @@
     expression.parent = this;
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -5888,19 +6956,30 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       expression.getStaticType(context);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitFileUriExpression(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitFileUriExpression(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     expression.accept(v);
   }
 
-  transformChildren(Transformer v) {
-    expression = expression.accept<TreeNode>(v)..parent = this;
+  @override
+  void transformChildren(Transformer v) {
+    expression = v.transform(expression)..parent = this;
   }
 
-  Location _getLocationInEnclosingFile(int offset) {
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    expression = v.transform(expression)..parent = this;
+  }
+
+  @override
+  Location? _getLocationInEnclosingFile(int offset) {
     return _getLocationInComponent(enclosingComponent, fileUri, offset);
   }
 
@@ -5927,7 +7006,7 @@
   DartType type;
 
   IsExpression(this.operand, this.type) {
-    operand?.parent = this;
+    operand.parent = this;
   }
 
   // Must match serialized bit positions.
@@ -5953,24 +7032,40 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitIsExpression(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitIsExpression(this, arg);
 
-  visitChildren(Visitor v) {
-    operand?.accept(v);
-    type?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    operand.accept(v);
+    type.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (operand != null) {
-      operand = operand.accept<TreeNode>(v);
-      operand?.parent = this;
+      operand = v.transform(operand);
+      operand.parent = this;
     }
     type = v.visitDartType(type);
   }
 
   @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (operand != null) {
+      operand = v.transform(operand);
+      operand.parent = this;
+    }
+    type = v.visitDartType(type, cannotRemoveSentinel);
+  }
+
+  @override
   String toString() {
     return "IsExpression(${toStringInternal()})";
   }
@@ -5995,7 +7090,7 @@
   DartType type;
 
   AsExpression(this.operand, this.type) {
-    operand?.parent = this;
+    operand.parent = this;
   }
 
   // Must match serialized bit positions.
@@ -6060,30 +7155,47 @@
         : (flags & ~FlagForNonNullableByDefault);
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
   @override
   DartType getStaticTypeInternal(StaticTypeContext context) => type;
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitAsExpression(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitAsExpression(this, arg);
 
-  visitChildren(Visitor v) {
-    operand?.accept(v);
-    type?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    operand.accept(v);
+    type.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (operand != null) {
-      operand = operand.accept<TreeNode>(v);
-      operand?.parent = this;
+      operand = v.transform(operand);
+      operand.parent = this;
     }
     type = v.visitDartType(type);
   }
 
   @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (operand != null) {
+      operand = v.transform(operand);
+      operand.parent = this;
+    }
+    type = v.visitDartType(type, cannotRemoveSentinel);
+  }
+
+  @override
   String toString() {
     return "AsExpression(${toStringInternal()})";
   }
@@ -6124,9 +7236,10 @@
   Expression operand;
 
   NullCheck(this.operand) {
-    operand?.parent = this;
+    operand.parent = this;
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
     DartType operandType = operand.getStaticType(context);
     return operandType is NullType
@@ -6134,18 +7247,33 @@
         : operandType.withDeclaredNullability(Nullability.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitNullCheck(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitNullCheck(this, arg);
 
-  visitChildren(Visitor v) {
-    operand?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    operand.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (operand != null) {
-      operand = operand.accept<TreeNode>(v);
-      operand?.parent = this;
+      operand = v.transform(operand);
+      operand.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (operand != null) {
+      operand = v.transform(operand);
+      operand.parent = this;
     }
   }
 
@@ -6164,17 +7292,25 @@
 
 /// An integer, double, boolean, string, or null constant.
 abstract class BasicLiteral extends Expression {
-  Object get value;
+  Object? get value;
 
-  visitChildren(Visitor v) {}
-  transformChildren(Transformer v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 }
 
 class StringLiteral extends BasicLiteral {
+  @override
   String value;
 
   StringLiteral(this.value);
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6182,7 +7318,10 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitStringLiteral(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitStringLiteral(this, arg);
 
@@ -6204,10 +7343,12 @@
   /// E.g. "0x8000000000000000" will be saved as "-9223372036854775808" despite
   /// technically (on some platforms, particularly Javascript) being positive.
   /// If the number is meant to be negative it will be wrapped in a "unary-".
+  @override
   int value;
 
   IntLiteral(this.value);
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6215,7 +7356,10 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.intRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitIntLiteral(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitIntLiteral(this, arg);
 
@@ -6231,10 +7375,12 @@
 }
 
 class DoubleLiteral extends BasicLiteral {
+  @override
   double value;
 
   DoubleLiteral(this.value);
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6242,7 +7388,10 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.doubleRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitDoubleLiteral(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitDoubleLiteral(this, arg);
 
@@ -6258,10 +7407,12 @@
 }
 
 class BoolLiteral extends BasicLiteral {
+  @override
   bool value;
 
   BoolLiteral(this.value);
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6269,7 +7420,10 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitBoolLiteral(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitBoolLiteral(this, arg);
 
@@ -6285,7 +7439,8 @@
 }
 
 class NullLiteral extends BasicLiteral {
-  Object get value => null;
+  @override
+  Object? get value => null;
 
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
@@ -6293,7 +7448,10 @@
   @override
   DartType getStaticTypeInternal(StaticTypeContext context) => const NullType();
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitNullLiteral(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitNullLiteral(this, arg);
 
@@ -6313,6 +7471,7 @@
 
   SymbolLiteral(this.value);
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6320,12 +7479,21 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.symbolRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitSymbolLiteral(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitSymbolLiteral(this, arg);
 
-  visitChildren(Visitor v) {}
-  transformChildren(Transformer v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -6344,6 +7512,7 @@
 
   TypeLiteral(this.type);
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6351,19 +7520,29 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.typeRawType(context.nonNullable);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitTypeLiteral(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitTypeLiteral(this, arg);
 
-  visitChildren(Visitor v) {
-    type?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    type.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     type = v.visitDartType(type);
   }
 
   @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    type = v.visitDartType(type, cannotRemoveSentinel);
+  }
+
+  @override
   String toString() {
     return "TypeLiteral(${toStringInternal()})";
   }
@@ -6379,14 +7558,24 @@
       getStaticTypeInternal(context);
 
   @override
-  DartType getStaticTypeInternal(StaticTypeContext context) => context.thisType;
+  DartType getStaticTypeInternal(StaticTypeContext context) =>
+      context.thisType!;
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitThisExpression(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitThisExpression(this, arg);
 
-  visitChildren(Visitor v) {}
-  transformChildren(Transformer v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -6400,6 +7589,7 @@
 }
 
 class Rethrow extends Expression {
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6409,12 +7599,21 @@
           ? const NeverType.nonNullable()
           : const BottomType();
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitRethrow(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitRethrow(this, arg);
 
-  visitChildren(Visitor v) {}
-  transformChildren(Transformer v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -6431,9 +7630,10 @@
   Expression expression;
 
   Throw(this.expression) {
-    expression?.parent = this;
+    expression.parent = this;
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6443,17 +7643,32 @@
           ? const NeverType.nonNullable()
           : const BottomType();
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitThrow(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitThrow(this, arg);
 
-  visitChildren(Visitor v) {
-    expression?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    expression.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
-      expression?.parent = this;
+      expression = v.transform(expression);
+      expression.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (expression != null) {
+      expression = v.transform(expression);
+      expression.parent = this;
     }
   }
 
@@ -6476,10 +7691,12 @@
 
   ListLiteral(this.expressions,
       {this.typeArgument: const DynamicType(), this.isConst: false}) {
+    // ignore: unnecessary_null_comparison
     assert(typeArgument != null);
     setParents(expressions, this);
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6488,18 +7705,29 @@
     return context.typeEnvironment.listType(typeArgument, context.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitListLiteral(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitListLiteral(this, arg);
 
-  visitChildren(Visitor v) {
-    typeArgument?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    typeArgument.accept(v);
     visitList(expressions, v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     typeArgument = v.visitDartType(typeArgument);
-    transformList(expressions, v, this);
+    v.transformList(expressions, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
+    v.transformExpressionList(expressions, this);
   }
 
   @override
@@ -6527,10 +7755,12 @@
 
   SetLiteral(this.expressions,
       {this.typeArgument: const DynamicType(), this.isConst: false}) {
+    // ignore: unnecessary_null_comparison
     assert(typeArgument != null);
     setParents(expressions, this);
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6539,18 +7769,29 @@
     return context.typeEnvironment.setType(typeArgument, context.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitSetLiteral(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitSetLiteral(this, arg);
 
-  visitChildren(Visitor v) {
-    typeArgument?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    typeArgument.accept(v);
     visitList(expressions, v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     typeArgument = v.visitDartType(typeArgument);
-    transformList(expressions, v, this);
+    v.transformList(expressions, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
+    v.transformExpressionList(expressions, this);
   }
 
   @override
@@ -6581,11 +7822,14 @@
       {this.keyType: const DynamicType(),
       this.valueType: const DynamicType(),
       this.isConst: false}) {
+    // ignore: unnecessary_null_comparison
     assert(keyType != null);
+    // ignore: unnecessary_null_comparison
     assert(valueType != null);
     setParents(entries, this);
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6595,20 +7839,32 @@
         .mapType(keyType, valueType, context.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitMapLiteral(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitMapLiteral(this, arg);
 
-  visitChildren(Visitor v) {
-    keyType?.accept(v);
-    valueType?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    keyType.accept(v);
+    valueType.accept(v);
     visitList(entries, v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     keyType = v.visitDartType(keyType);
     valueType = v.visitDartType(valueType);
-    transformList(entries, v, this);
+    v.transformList(entries, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    keyType = v.visitDartType(keyType, cannotRemoveSentinel);
+    valueType = v.visitDartType(valueType, cannotRemoveSentinel);
+    v.transformMapEntryList(entries, this);
   }
 
   @override
@@ -6641,25 +7897,47 @@
   Expression value;
 
   MapEntry(this.key, this.value) {
-    key?.parent = this;
-    value?.parent = this;
+    key.parent = this;
+    value.parent = this;
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitMapEntry(this);
 
-  visitChildren(Visitor v) {
-    key?.accept(v);
-    value?.accept(v);
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitMapEntry(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
+    key.accept(v);
+    value.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (key != null) {
-      key = key.accept<TreeNode>(v);
-      key?.parent = this;
+      key = v.transform(key);
+      key.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (value != null) {
-      value = value.accept<TreeNode>(v);
-      value?.parent = this;
+      value = v.transform(value);
+      value.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (key != null) {
+      key = v.transform(key);
+      key.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (value != null) {
+      value = v.transform(value);
+      value.parent = this;
     }
   }
 
@@ -6686,25 +7964,41 @@
   Expression operand;
 
   AwaitExpression(this.operand) {
-    operand?.parent = this;
+    operand.parent = this;
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
     return context.typeEnvironment.flatten(operand.getStaticType(context));
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitAwaitExpression(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitAwaitExpression(this, arg);
 
-  visitChildren(Visitor v) {
-    operand?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    operand.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (operand != null) {
-      operand = operand.accept<TreeNode>(v);
-      operand?.parent = this;
+      operand = v.transform(operand);
+      operand.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (operand != null) {
+      operand = v.transform(operand);
+      operand.parent = this;
     }
   }
 
@@ -6722,35 +8016,53 @@
 
 /// Common super-interface for [FunctionExpression] and [FunctionDeclaration].
 abstract class LocalFunction implements TreeNode {
-  FunctionNode get function;
+  // TODO(johnniwinther): Make this non-nullable.
+  FunctionNode? get function;
 }
 
 /// Expression of form `(x,y) => ...` or `(x,y) { ... }`
 ///
 /// The arrow-body form `=> e` is desugared into `return e;`.
 class FunctionExpression extends Expression implements LocalFunction {
+  @override
   FunctionNode function;
 
   FunctionExpression(this.function) {
-    function?.parent = this;
+    function.parent = this;
   }
 
+  @override
   DartType getStaticTypeInternal(StaticTypeContext context) {
     return function.computeFunctionType(context.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionExpression(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitFunctionExpression(this, arg);
 
-  visitChildren(Visitor v) {
-    function?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    function.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (function != null) {
-      function = function.accept<TreeNode>(v);
-      function?.parent = this;
+      function = v.transform(function);
+      function.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (function != null) {
+      function = v.transform(function);
+      function.parent = this;
     }
   }
 
@@ -6770,30 +8082,43 @@
   DartType type;
 
   ConstantExpression(this.constant, [this.type = const DynamicType()]) {
+    // ignore: unnecessary_null_comparison
     assert(constant != null);
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
   @override
   DartType getStaticTypeInternal(StaticTypeContext context) => type;
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitConstantExpression(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitConstantExpression(this, arg);
 
-  visitChildren(Visitor v) {
-    constant?.acceptReference(v);
-    type?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    constant.acceptReference(v);
+    type.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     constant = v.visitConstant(constant);
     type = v.visitDartType(type);
   }
 
   @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    constant = v.visitConstant(constant, cannotRemoveSentinel);
+    type = v.visitDartType(type, cannotRemoveSentinel);
+  }
+
+  @override
   String toString() {
     return "ConstantExpression(${toStringInternal()})";
   }
@@ -6810,10 +8135,11 @@
   Expression body;
 
   Let(this.variable, this.body) {
-    variable?.parent = this;
-    body?.parent = this;
+    variable.parent = this;
+    body.parent = this;
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6821,22 +8147,43 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       body.getStaticType(context);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitLet(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitLet(this, arg);
 
-  visitChildren(Visitor v) {
-    variable?.accept(v);
-    body?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    variable.accept(v);
+    body.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
-      variable?.parent = this;
+      variable = v.transform(variable);
+      variable.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (body != null) {
-      body = body.accept<TreeNode>(v);
-      body?.parent = this;
+      body = v.transform(body);
+      body.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (variable != null) {
+      variable = v.transform(variable);
+      variable.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (body != null) {
+      body = v.transform(body);
+      body.parent = this;
     }
   }
 
@@ -6859,10 +8206,11 @@
   Expression value;
 
   BlockExpression(this.body, this.value) {
-    body?.parent = this;
-    value?.parent = this;
+    body.parent = this;
+    value.parent = this;
   }
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6870,23 +8218,44 @@
   DartType getStaticTypeInternal(StaticTypeContext context) =>
       value.getStaticType(context);
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitBlockExpression(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitBlockExpression(this, arg);
 
-  visitChildren(Visitor v) {
-    body?.accept(v);
-    value?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    body.accept(v);
+    value.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (body != null) {
-      body = body.accept<TreeNode>(v);
-      body?.parent = this;
+      body = v.transform(body);
+      body.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (value != null) {
-      value = value.accept<TreeNode>(v);
-      value?.parent = this;
+      value = v.transform(value);
+      value.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (body != null) {
+      body = v.transform(body);
+      body.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (value != null) {
+      value = v.transform(value);
+      value.parent = this;
     }
   }
 
@@ -6922,6 +8291,7 @@
 
   LoadLibrary(this.import);
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6931,12 +8301,21 @@
         .futureType(const DynamicType(), context.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitLoadLibrary(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitLoadLibrary(this, arg);
 
-  visitChildren(Visitor v) {}
-  transformChildren(Transformer v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -6945,7 +8324,7 @@
 
   @override
   void toTextInternal(AstPrinter printer) {
-    printer.write(import.name);
+    printer.write(import.name!);
     printer.write('.loadLibrary()');
   }
 }
@@ -6957,6 +8336,7 @@
 
   CheckLibraryIsLoaded(this.import);
 
+  @override
   DartType getStaticType(StaticTypeContext context) =>
       getStaticTypeInternal(context);
 
@@ -6965,12 +8345,21 @@
     return context.typeEnvironment.coreTypes.objectRawType(context.nonNullable);
   }
 
+  @override
   R accept<R>(ExpressionVisitor<R> v) => v.visitCheckLibraryIsLoaded(this);
+
+  @override
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitCheckLibraryIsLoaded(this, arg);
 
-  visitChildren(Visitor v) {}
-  transformChildren(Transformer v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -6979,7 +8368,7 @@
 
   @override
   void toTextInternal(AstPrinter printer) {
-    printer.write(import.name);
+    printer.write(import.name!);
     printer.write('.checkLibraryIsLoaded()');
   }
 }
@@ -6989,11 +8378,13 @@
 // ------------------------------------------------------------------------
 
 abstract class Statement extends TreeNode {
+  @override
   R accept<R>(StatementVisitor<R> v);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg);
 
-  void toTextInternal(AstPrinter printer);
-
+  @override
   String toText(AstTextStrategy strategy) {
     AstPrinter printer = new AstPrinter(strategy);
     printer.writeStatement(this);
@@ -7005,21 +8396,36 @@
   Expression expression;
 
   ExpressionStatement(this.expression) {
-    expression?.parent = this;
+    expression.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitExpressionStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitExpressionStatement(this, arg);
 
-  visitChildren(Visitor v) {
-    expression?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    expression.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
-      expression?.parent = this;
+      expression = v.transform(expression);
+      expression.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (expression != null) {
+      expression = v.transform(expression);
+      expression.parent = this;
     }
   }
 
@@ -7045,22 +8451,29 @@
 
   Block(this.statements) {
     // Ensure statements is mutable.
-    assert((statements
-          ..add(null)
-          ..removeLast()) !=
-        null);
+    assert(checkListIsMutable(statements, dummyStatement));
     setParents(statements, this);
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitBlock(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) => v.visitBlock(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     visitList(statements, v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(statements, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(statements, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformStatementList(statements, this);
   }
 
   void addStatement(Statement node) {
@@ -7089,22 +8502,29 @@
 
   AssertBlock(this.statements) {
     // Ensure statements is mutable.
-    assert((statements
-          ..add(null)
-          ..removeLast()) !=
-        null);
+    assert(checkListIsMutable(statements, dummyStatement));
     setParents(statements, this);
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitAssertBlock(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitAssertBlock(this, arg);
 
-  transformChildren(Transformer v) {
-    transformList(statements, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(statements, this);
   }
 
-  visitChildren(Visitor v) {
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformStatementList(statements, this);
+  }
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(statements, v);
   }
 
@@ -7126,12 +8546,21 @@
 }
 
 class EmptyStatement extends Statement {
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitEmptyStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitEmptyStatement(this, arg);
 
-  visitChildren(Visitor v) {}
-  transformChildren(Transformer v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -7146,7 +8575,7 @@
 
 class AssertStatement extends Statement {
   Expression condition;
-  Expression message; // May be null.
+  Expression? message; // May be null.
 
   /// Character offset in the source where the assertion condition begins.
   ///
@@ -7159,27 +8588,48 @@
   int conditionEndOffset;
 
   AssertStatement(this.condition,
-      {this.message, this.conditionStartOffset, this.conditionEndOffset}) {
-    condition?.parent = this;
+      {this.message,
+      required this.conditionStartOffset,
+      required this.conditionEndOffset}) {
+    condition.parent = this;
     message?.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitAssertStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitAssertStatement(this, arg);
 
-  visitChildren(Visitor v) {
-    condition?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    condition.accept(v);
     message?.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (condition != null) {
-      condition = condition.accept<TreeNode>(v);
-      condition?.parent = this;
+      condition = v.transform(condition);
+      condition.parent = this;
     }
     if (message != null) {
-      message = message.accept<TreeNode>(v);
+      message = v.transform(message!);
+      message?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (condition != null) {
+      condition = v.transform(condition);
+      condition.parent = this;
+    }
+    if (message != null) {
+      message = v.transformOrRemoveExpression(message!);
       message?.parent = this;
     }
   }
@@ -7195,7 +8645,7 @@
     printer.writeExpression(condition);
     if (message != null) {
       printer.write(', ');
-      printer.writeExpression(message);
+      printer.writeExpression(message!);
     }
     printer.write(');');
   }
@@ -7207,23 +8657,37 @@
 ///
 /// The frontend does not generate labeled statements without uses.
 class LabeledStatement extends Statement {
-  Statement body;
+  // TODO(johnniwinther): Make this non-nullable.
+  Statement? body;
 
   LabeledStatement(this.body) {
     body?.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitLabeledStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitLabeledStatement(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     body?.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     if (body != null) {
-      body = body.accept<TreeNode>(v);
+      body = v.transform(body!);
+      body?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (body != null) {
+      body = v.transformOrRemoveStatement(body!);
       body?.parent = this;
     }
   }
@@ -7238,7 +8702,7 @@
     printer.write(printer.getLabelName(this));
     printer.write(':');
     printer.newLine();
-    printer.writeStatement(body);
+    printer.writeStatement(body!);
   }
 }
 
@@ -7267,12 +8731,21 @@
 
   BreakStatement(this.target);
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitBreakStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitBreakStatement(this, arg);
 
-  visitChildren(Visitor v) {}
-  transformChildren(Transformer v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -7292,27 +8765,48 @@
   Statement body;
 
   WhileStatement(this.condition, this.body) {
-    condition?.parent = this;
-    body?.parent = this;
+    condition.parent = this;
+    body.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitWhileStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitWhileStatement(this, arg);
 
-  visitChildren(Visitor v) {
-    condition?.accept(v);
-    body?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    condition.accept(v);
+    body.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (condition != null) {
-      condition = condition.accept<TreeNode>(v);
-      condition?.parent = this;
+      condition = v.transform(condition);
+      condition.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (body != null) {
-      body = body.accept<TreeNode>(v);
-      body?.parent = this;
+      body = v.transform(body);
+      body.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (condition != null) {
+      condition = v.transform(condition);
+      condition.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (body != null) {
+      body = v.transform(body);
+      body.parent = this;
     }
   }
 
@@ -7335,27 +8829,48 @@
   Expression condition;
 
   DoStatement(this.body, this.condition) {
-    body?.parent = this;
-    condition?.parent = this;
+    body.parent = this;
+    condition.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitDoStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitDoStatement(this, arg);
 
-  visitChildren(Visitor v) {
-    body?.accept(v);
-    condition?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    body.accept(v);
+    condition.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (body != null) {
-      body = body.accept<TreeNode>(v);
-      body?.parent = this;
+      body = v.transform(body);
+      body.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (condition != null) {
-      condition = condition.accept<TreeNode>(v);
-      condition?.parent = this;
+      condition = v.transform(condition);
+      condition.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (body != null) {
+      body = v.transform(body);
+      body.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (condition != null) {
+      condition = v.transform(condition);
+      condition.parent = this;
     }
   }
 
@@ -7376,7 +8891,7 @@
 
 class ForStatement extends Statement {
   final List<VariableDeclaration> variables; // May be empty, but not null.
-  Expression condition; // May be null.
+  Expression? condition; // May be null.
   final List<Expression> updates; // May be empty, but not null.
   Statement body;
 
@@ -7384,30 +8899,51 @@
     setParents(variables, this);
     condition?.parent = this;
     setParents(updates, this);
-    body?.parent = this;
+    body.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitForStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitForStatement(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     visitList(variables, v);
     condition?.accept(v);
     visitList(updates, v);
-    body?.accept(v);
+    body.accept(v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(variables, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(variables, this);
     if (condition != null) {
-      condition = condition.accept<TreeNode>(v);
+      condition = v.transform(condition!);
       condition?.parent = this;
     }
-    transformList(updates, v, this);
+    v.transformList(updates, this);
+    // ignore: unnecessary_null_comparison
     if (body != null) {
-      body = body.accept<TreeNode>(v);
-      body?.parent = this;
+      body = v.transform(body);
+      body.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformVariableDeclarationList(variables, this);
+    if (condition != null) {
+      condition = v.transformOrRemoveExpression(condition!);
+      condition?.parent = this;
+    }
+    v.transformExpressionList(updates, this);
+    // ignore: unnecessary_null_comparison
+    if (body != null) {
+      body = v.transform(body);
+      body.parent = this;
     }
   }
 
@@ -7428,7 +8964,7 @@
     }
     printer.write('; ');
     if (condition != null) {
-      printer.writeExpression(condition);
+      printer.writeExpression(condition!);
     }
     printer.write('; ');
     printer.writeExpressions(updates);
@@ -7451,33 +8987,60 @@
 
   ForInStatement(this.variable, this.iterable, this.body,
       {this.isAsync: false}) {
-    variable?.parent = this;
-    iterable?.parent = this;
-    body?.parent = this;
+    variable.parent = this;
+    iterable.parent = this;
+    body.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitForInStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitForInStatement(this, arg);
 
+  @override
   void visitChildren(Visitor v) {
-    variable?.accept(v);
-    iterable?.accept(v);
-    body?.accept(v);
+    variable.accept(v);
+    iterable.accept(v);
+    body.accept(v);
   }
 
+  @override
   void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
-      variable?.parent = this;
+      variable = v.transform(variable);
+      variable.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (iterable != null) {
-      iterable = iterable.accept<TreeNode>(v);
-      iterable?.parent = this;
+      iterable = v.transform(iterable);
+      iterable.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (body != null) {
-      body = body.accept<TreeNode>(v);
-      body?.parent = this;
+      body = v.transform(body);
+      body.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (variable != null) {
+      variable = v.transform(variable);
+      variable.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (iterable != null) {
+      iterable = v.transform(iterable);
+      iterable.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (body != null) {
+      body = v.transform(body);
+      body.parent = this;
     }
   }
 
@@ -7494,10 +9057,11 @@
   /// This is called by `StaticTypeContext.getForInIteratorType` if the iterator
   /// type of this for-in statement is not already cached in [context].
   DartType getIteratorTypeInternal(StaticTypeContext context) {
-    DartType iteratorType;
+    DartType? iteratorType;
     if (isAsync) {
-      InterfaceType streamType = iterable.getStaticTypeAsInstanceOf(
+      InterfaceType? streamType = iterable.getStaticTypeAsInstanceOf(
           context.typeEnvironment.coreTypes.streamClass, context);
+      // ignore: unnecessary_null_comparison
       if (streamType != null) {
         iteratorType = new InterfaceType(
             context.typeEnvironment.coreTypes.streamIteratorClass,
@@ -7507,14 +9071,14 @@
     } else {
       InterfaceType iterableType = iterable.getStaticTypeAsInstanceOf(
           context.typeEnvironment.coreTypes.iterableClass, context);
-      Member member = context.typeEnvironment.hierarchy
+      Member? member = context.typeEnvironment.hierarchy
           .getInterfaceMember(iterableType.classNode, new Name('iterator'));
       if (member != null) {
         iteratorType = Substitution.fromInterfaceType(iterableType)
             .substituteType(member.getterType);
       }
     }
-    return iteratorType ??= const DynamicType();
+    return iteratorType ?? const DynamicType();
   }
 
   /// Returns the type of the element in this for-in statement.
@@ -7535,18 +9099,17 @@
     //  `iterable.iterator.current` if inference is updated accordingly.
     while (iterableType is TypeParameterType) {
       TypeParameterType typeParameterType = iterableType;
-      iterableType =
-          typeParameterType.promotedBound ?? typeParameterType.parameter.bound;
+      iterableType = typeParameterType.bound;
     }
     if (isAsync) {
       List<DartType> typeArguments = context.typeEnvironment
-          .getTypeArgumentsAsInstanceOf(
-              iterableType, context.typeEnvironment.coreTypes.streamClass);
+          .getTypeArgumentsAsInstanceOf(iterableType as InterfaceType,
+              context.typeEnvironment.coreTypes.streamClass)!;
       return typeArguments.single;
     } else {
       List<DartType> typeArguments = context.typeEnvironment
-          .getTypeArgumentsAsInstanceOf(
-              iterableType, context.typeEnvironment.coreTypes.iterableClass);
+          .getTypeArgumentsAsInstanceOf(iterableType as InterfaceType,
+              context.typeEnvironment.coreTypes.iterableClass)!;
       return typeArguments.single;
     }
   }
@@ -7577,25 +9140,41 @@
   final List<SwitchCase> cases;
 
   SwitchStatement(this.expression, this.cases) {
-    expression?.parent = this;
+    expression.parent = this;
     setParents(cases, this);
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitSwitchStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitSwitchStatement(this, arg);
 
-  visitChildren(Visitor v) {
-    expression?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    expression.accept(v);
     visitList(cases, v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
-      expression?.parent = this;
+      expression = v.transform(expression);
+      expression.parent = this;
     }
-    transformList(cases, v, this);
+    v.transformList(cases, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (expression != null) {
+      expression = v.transform(expression);
+      expression.parent = this;
+    }
+    v.transformSwitchCaseList(cases, this);
   }
 
   @override
@@ -7625,7 +9204,8 @@
 class SwitchCase extends TreeNode {
   final List<Expression> expressions;
   final List<int> expressionOffsets;
-  Statement body;
+  // TODO(johnniwinther): Make this non-nullable.
+  Statement? body;
   bool isDefault;
 
   SwitchCase(this.expressions, this.expressionOffsets, this.body,
@@ -7647,17 +9227,32 @@
         body = null,
         isDefault = false;
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitSwitchCase(this);
 
-  visitChildren(Visitor v) {
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitSwitchCase(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(expressions, v);
     body?.accept(v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(expressions, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(expressions, this);
     if (body != null) {
-      body = body.accept<TreeNode>(v);
+      body = v.transform(body!);
+      body?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(expressions, this);
+    if (body != null) {
+      body = v.transformOrRemoveStatement(body!);
       body?.parent = this;
     }
   }
@@ -7667,12 +9262,14 @@
     return "SwitchCase(${toStringInternal()})";
   }
 
+  @override
   String toText(AstTextStrategy strategy) {
     AstPrinter printer = new AstPrinter(strategy);
     toTextInternal(printer);
     return printer.getText();
   }
 
+  @override
   void toTextInternal(AstPrinter printer) {
     for (int index = 0; index < expressions.length; index++) {
       if (index > 0) {
@@ -7689,7 +9286,7 @@
       printer.write('default:');
     }
     printer.incIndentation();
-    Statement block = body;
+    Statement? block = body;
     if (block is Block) {
       for (Statement statement in block.statements) {
         printer.newLine();
@@ -7697,7 +9294,7 @@
       }
     } else {
       printer.write(' ');
-      printer.writeStatement(body);
+      printer.writeStatement(body!);
     }
     printer.decIndentation();
   }
@@ -7709,12 +9306,21 @@
 
   ContinueSwitchStatement(this.target);
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitContinueSwitchStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitContinueSwitchStatement(this, arg);
 
-  visitChildren(Visitor v) {}
-  transformChildren(Transformer v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
 
   @override
   String toString() {
@@ -7732,35 +9338,60 @@
 class IfStatement extends Statement {
   Expression condition;
   Statement then;
-  Statement otherwise;
+  Statement? otherwise;
 
   IfStatement(this.condition, this.then, this.otherwise) {
-    condition?.parent = this;
-    then?.parent = this;
+    condition.parent = this;
+    then.parent = this;
     otherwise?.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitIfStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitIfStatement(this, arg);
 
-  visitChildren(Visitor v) {
-    condition?.accept(v);
-    then?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    condition.accept(v);
+    then.accept(v);
     otherwise?.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (condition != null) {
-      condition = condition.accept<TreeNode>(v);
-      condition?.parent = this;
+      condition = v.transform(condition);
+      condition.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (then != null) {
-      then = then.accept<TreeNode>(v);
-      then?.parent = this;
+      then = v.transform(then);
+      then.parent = this;
     }
     if (otherwise != null) {
-      otherwise = otherwise.accept<TreeNode>(v);
+      otherwise = v.transform(otherwise!);
+      otherwise?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (condition != null) {
+      condition = v.transform(condition);
+      condition.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (then != null) {
+      then = v.transform(then);
+      then.parent = this;
+    }
+    if (otherwise != null) {
+      otherwise = v.transformOrRemoveStatement(otherwise!);
       otherwise?.parent = this;
     }
   }
@@ -7778,29 +9409,42 @@
     printer.writeStatement(then);
     if (otherwise != null) {
       printer.write(' else ');
-      printer.writeStatement(otherwise);
+      printer.writeStatement(otherwise!);
     }
   }
 }
 
 class ReturnStatement extends Statement {
-  Expression expression; // May be null.
+  Expression? expression; // May be null.
 
   ReturnStatement([this.expression]) {
     expression?.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitReturnStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitReturnStatement(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     expression?.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
+      expression = v.transform(expression!);
+      expression?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    if (expression != null) {
+      expression = v.transformOrRemoveExpression(expression!);
       expression?.parent = this;
     }
   }
@@ -7815,7 +9459,7 @@
     printer.write('return');
     if (expression != null) {
       printer.write(' ');
-      printer.writeExpression(expression);
+      printer.writeExpression(expression!);
     }
     printer.write(';');
   }
@@ -7827,25 +9471,41 @@
   bool isSynthetic;
 
   TryCatch(this.body, this.catches, {this.isSynthetic: false}) {
-    body?.parent = this;
+    body.parent = this;
     setParents(catches, this);
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitTryCatch(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitTryCatch(this, arg);
 
-  visitChildren(Visitor v) {
-    body?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    body.accept(v);
     visitList(catches, v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (body != null) {
-      body = body.accept<TreeNode>(v);
-      body?.parent = this;
+      body = v.transform(body);
+      body.parent = this;
     }
-    transformList(catches, v, this);
+    v.transformList(catches, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (body != null) {
+      body = v.transform(body);
+      body.parent = this;
+    }
+    v.transformCatchList(catches, this);
   }
 
   @override
@@ -7866,40 +9526,66 @@
 
 class Catch extends TreeNode {
   DartType guard; // Not null, defaults to dynamic.
-  VariableDeclaration exception; // May be null.
-  VariableDeclaration stackTrace; // May be null.
+  VariableDeclaration? exception;
+  VariableDeclaration? stackTrace;
   Statement body;
 
   Catch(this.exception, this.body,
       {this.guard: const DynamicType(), this.stackTrace}) {
+    // ignore: unnecessary_null_comparison
     assert(guard != null);
     exception?.parent = this;
     stackTrace?.parent = this;
-    body?.parent = this;
+    body.parent = this;
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitCatch(this);
 
-  visitChildren(Visitor v) {
-    guard?.accept(v);
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitCatch(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
+    guard.accept(v);
     exception?.accept(v);
     stackTrace?.accept(v);
-    body?.accept(v);
+    body.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
     guard = v.visitDartType(guard);
     if (exception != null) {
-      exception = exception.accept<TreeNode>(v);
+      exception = v.transform(exception!);
       exception?.parent = this;
     }
     if (stackTrace != null) {
-      stackTrace = stackTrace.accept<TreeNode>(v);
+      stackTrace = v.transform(stackTrace!);
       stackTrace?.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (body != null) {
-      body = body.accept<TreeNode>(v);
-      body?.parent = this;
+      body = v.transform(body);
+      body.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    guard = v.visitDartType(guard, cannotRemoveSentinel);
+    if (exception != null) {
+      exception = v.transformOrRemoveVariableDeclaration(exception!);
+      exception?.parent = this;
+    }
+    if (stackTrace != null) {
+      stackTrace = v.transformOrRemoveVariableDeclaration(stackTrace!);
+      stackTrace?.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (body != null) {
+      body = v.transform(body);
+      body.parent = this;
     }
   }
 
@@ -7908,12 +9594,14 @@
     return "Catch(${toStringInternal()})";
   }
 
+  @override
   String toText(AstTextStrategy strategy) {
     AstPrinter printer = new AstPrinter(strategy);
     toTextInternal(printer);
     return printer.getText();
   }
 
+  @override
   void toTextInternal(AstPrinter printer) {
     bool isImplicitType(DartType type) {
       if (type is DynamicType) {
@@ -7922,9 +9610,9 @@
       if (type is InterfaceType &&
           type.className.node != null &&
           type.classNode.name == 'Object') {
-        Uri uri = type.classNode.enclosingLibrary?.importUri;
-        return uri?.scheme == 'dart' &&
-            uri?.path == 'core' &&
+        Uri uri = type.classNode.enclosingLibrary.importUri;
+        return uri.scheme == 'dart' &&
+            uri.path == 'core' &&
             type.nullability == Nullability.nonNullable;
       }
       return false;
@@ -7937,11 +9625,11 @@
         printer.write(' ');
       }
       printer.write('catch (');
-      printer.writeVariableDeclaration(exception,
+      printer.writeVariableDeclaration(exception!,
           includeModifiersAndType: false);
       if (stackTrace != null) {
         printer.write(', ');
-        printer.writeVariableDeclaration(stackTrace,
+        printer.writeVariableDeclaration(stackTrace!,
             includeModifiersAndType: false);
       }
       printer.write(') ');
@@ -7959,27 +9647,48 @@
   Statement finalizer;
 
   TryFinally(this.body, this.finalizer) {
-    body?.parent = this;
-    finalizer?.parent = this;
+    body.parent = this;
+    finalizer.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitTryFinally(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitTryFinally(this, arg);
 
-  visitChildren(Visitor v) {
-    body?.accept(v);
-    finalizer?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    body.accept(v);
+    finalizer.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (body != null) {
-      body = body.accept<TreeNode>(v);
-      body?.parent = this;
+      body = v.transform(body);
+      body.parent = this;
     }
+    // ignore: unnecessary_null_comparison
     if (finalizer != null) {
-      finalizer = finalizer.accept<TreeNode>(v);
-      finalizer?.parent = this;
+      finalizer = v.transform(finalizer);
+      finalizer.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (body != null) {
+      body = v.transform(body);
+      body.parent = this;
+    }
+    // ignore: unnecessary_null_comparison
+    if (finalizer != null) {
+      finalizer = v.transform(finalizer);
+      finalizer.parent = this;
     }
   }
 
@@ -8009,7 +9718,7 @@
 
   YieldStatement(this.expression,
       {bool isYieldStar: false, bool isNative: false}) {
-    expression?.parent = this;
+    expression.parent = this;
     this.isYieldStar = isYieldStar;
     this.isNative = isNative;
   }
@@ -8028,18 +9737,33 @@
     flags = value ? (flags | FlagNative) : (flags & ~FlagNative);
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitYieldStatement(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitYieldStatement(this, arg);
 
-  visitChildren(Visitor v) {
-    expression?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    expression.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (expression != null) {
-      expression = expression.accept<TreeNode>(v);
-      expression?.parent = this;
+      expression = v.transform(expression);
+      expression.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (expression != null) {
+      expression = v.transform(expression);
+      expression.parent = this;
     }
   }
 
@@ -8087,7 +9811,7 @@
   ///
   /// In all other cases, the name is cosmetic, may be empty or null,
   /// and is not necessarily unique.
-  String name;
+  String? name;
   int flags = 0;
   DartType type; // Not null, defaults to dynamic.
 
@@ -8098,7 +9822,7 @@
   /// For parameters, this is the default value.
   ///
   /// Should be null in other cases.
-  Expression initializer; // May be null.
+  Expression? initializer; // May be null.
 
   VariableDeclaration(this.name,
       {this.initializer,
@@ -8111,6 +9835,7 @@
       bool isLate: false,
       bool isRequired: false,
       bool isLowered: false}) {
+    // ignore: unnecessary_null_comparison
     assert(type != null);
     initializer?.parent = this;
     if (flags != -1) {
@@ -8135,6 +9860,7 @@
       bool isRequired: false,
       bool isLowered: false,
       this.type: const DynamicType()}) {
+    // ignore: unnecessary_null_comparison
     assert(type != null);
     initializer?.parent = this;
     this.isFinal = isFinal;
@@ -8254,27 +9980,43 @@
     annotations.add(annotation..parent = this);
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitVariableDeclaration(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitVariableDeclaration(this, arg);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
-    type?.accept(v);
+    type.accept(v);
     initializer?.accept(v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(annotations, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(annotations, this);
     type = v.visitDartType(type);
     if (initializer != null) {
-      initializer = initializer.accept<TreeNode>(v);
+      initializer = v.transform(initializer!);
+      initializer?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(annotations, this);
+    type = v.visitDartType(type, cannotRemoveSentinel);
+    if (initializer != null) {
+      initializer = v.transformOrRemoveExpression(initializer!);
       initializer?.parent = this;
     }
   }
 
   /// Returns a possibly synthesized name for this variable, consistent with
   /// the names used across all [toString] calls.
+  @override
   String toString() {
     return "VariableDeclaration(${toStringInternal()})";
   }
@@ -8298,29 +10040,50 @@
 /// The body of the function may use [variable] as its self-reference.
 class FunctionDeclaration extends Statement implements LocalFunction {
   VariableDeclaration variable; // Is final and has no initializer.
-  FunctionNode function;
+
+  @override
+  FunctionNode? function;
 
   FunctionDeclaration(this.variable, this.function) {
-    variable?.parent = this;
+    variable.parent = this;
     function?.parent = this;
   }
 
+  @override
   R accept<R>(StatementVisitor<R> v) => v.visitFunctionDeclaration(this);
+
+  @override
   R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitFunctionDeclaration(this, arg);
 
-  visitChildren(Visitor v) {
-    variable?.accept(v);
+  @override
+  void visitChildren(Visitor v) {
+    variable.accept(v);
     function?.accept(v);
   }
 
-  transformChildren(Transformer v) {
+  @override
+  void transformChildren(Transformer v) {
+    // ignore: unnecessary_null_comparison
     if (variable != null) {
-      variable = variable.accept<TreeNode>(v);
-      variable?.parent = this;
+      variable = v.transform(variable);
+      variable.parent = this;
     }
     if (function != null) {
-      function = function.accept<TreeNode>(v);
+      function = v.transform(function!);
+      function?.parent = this;
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    // ignore: unnecessary_null_comparison
+    if (variable != null) {
+      variable = v.transform(variable);
+      variable.parent = this;
+    }
+    if (function != null) {
+      function = v.transformOrRemove(function!, dummyFunctionNode);
       function?.parent = this;
     }
   }
@@ -8332,9 +10095,11 @@
 
   @override
   void toTextInternal(AstPrinter printer) {
-    printer.writeFunctionNode(function, printer.getVariableName(variable));
-    if (function.body is ReturnStatement) {
-      printer.write(';');
+    if (function != null) {
+      printer.writeFunctionNode(function!, printer.getVariableName(variable));
+      if (function!.body is ReturnStatement) {
+        printer.write(';');
+      }
     }
   }
 }
@@ -8354,23 +10119,25 @@
 /// The [toString] method returns a human-readable string that includes the
 /// library name for private names; uniqueness is not guaranteed.
 abstract class Name extends Node {
+  @override
   final int hashCode;
+
   final String text;
-  Reference get libraryName;
-  Library get library;
+  Reference? get libraryName;
+  Library? get library;
   bool get isPrivate;
 
   Name._internal(this.hashCode, this.text);
 
-  factory Name(String text, [Library library]) =>
+  factory Name(String text, [Library? library]) =>
       new Name.byReference(text, library?.reference);
 
-  factory Name.byReference(String text, Reference libraryName) {
+  factory Name.byReference(String text, Reference? libraryName) {
     /// Use separate subclasses for the public and private case to save memory
     /// for public names.
     if (text.startsWith('_')) {
       assert(libraryName != null);
-      return new _PrivateName(text, libraryName);
+      return new _PrivateName(text, libraryName!);
     } else {
       return new _PublicName(text);
     }
@@ -8380,13 +10147,16 @@
   // use [text].
   String get name => text;
 
+  @override
   bool operator ==(other) {
     return other is Name && text == other.text && library == other.library;
   }
 
+  @override
   R accept<R>(Visitor<R> v) => v.visitName(this);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     // DESIGN TODO: Should we visit the library as a library reference?
   }
 
@@ -8394,6 +10164,7 @@
   ///
   /// Note that this adds some nodes to a static map to ensure consistent
   /// naming, but that it thus also leaks memory.
+  @override
   String leakingDebugToString() => astToText.debugNodeToString(this);
 
   @override
@@ -8409,17 +10180,25 @@
 }
 
 class _PrivateName extends Name {
+  @override
   final Reference libraryName;
+
+  @override
   bool get isPrivate => true;
 
   _PrivateName(String text, Reference libraryName)
       : this.libraryName = libraryName,
         super._internal(_computeHashCode(text, libraryName), text);
 
+  @override
   String toString() => toStringInternal();
 
-  String toStringInternal() => library != null ? '$library::$text' : text;
+  @override
+  String toStringInternal() =>
+      // ignore: unnecessary_null_comparison
+      library != null ? '$library::$text' : text;
 
+  @override
   Library get library => libraryName.asLibrary;
 
   static int _computeHashCode(String name, Reference libraryName) {
@@ -8431,12 +10210,18 @@
 }
 
 class _PublicName extends Name {
-  Reference get libraryName => null;
-  Library get library => null;
+  @override
+  Reference? get libraryName => null;
+
+  @override
+  Library? get library => null;
+
+  @override
   bool get isPrivate => false;
 
   _PublicName(String text) : super._internal(text.hashCode, text);
 
+  @override
   String toString() => toStringInternal();
 }
 
@@ -8554,17 +10339,19 @@
         nullability == Nullability.undetermined;
   }
 
-  bool equals(Object other, Assumptions assumptions);
+  bool equals(Object other, Assumptions? assumptions);
 
   /// Returns a textual representation of the this type.
   ///
   /// If [verbose] is `true`, qualified names will include the library name/uri.
+  @override
   String toText(AstTextStrategy strategy) {
     AstPrinter printer = new AstPrinter(strategy);
     printer.writeType(this);
     return printer.getText();
   }
 
+  @override
   void toTextInternal(AstPrinter printer);
 }
 
@@ -8592,7 +10379,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) => other is InvalidType;
+  bool equals(Object other, Assumptions? assumptions) => other is InvalidType;
 
   @override
   Nullability get declaredNullability {
@@ -8640,7 +10427,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) => other is DynamicType;
+  bool equals(Object other, Assumptions? assumptions) => other is DynamicType;
 
   @override
   Nullability get declaredNullability => Nullability.nullable;
@@ -8682,7 +10469,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) => other is VoidType;
+  bool equals(Object other, Assumptions? assumptions) => other is VoidType;
 
   @override
   Nullability get declaredNullability => Nullability.nullable;
@@ -8729,7 +10516,6 @@
       case Nullability.undetermined:
         return const NeverType.undetermined();
     }
-    throw new StateError("Unhandled nullability value '${nullability}'.");
   }
 
   @override
@@ -8754,7 +10540,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) =>
+  bool equals(Object other, Assumptions? assumptions) =>
       other is NeverType && nullability == other.nullability;
 
   @override
@@ -8796,7 +10582,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) => other is BottomType;
+  bool equals(Object other, Assumptions? assumptions) => other is BottomType;
 
   @override
   Nullability get declaredNullability => Nullability.nonNullable;
@@ -8839,7 +10625,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) => other is NullType;
+  bool equals(Object other, Assumptions? assumptions) => other is NullType;
 
   @override
   Nullability get declaredNullability => Nullability.nullable;
@@ -8872,12 +10658,15 @@
   /// The [typeArguments] list must not be modified after this call. If the
   /// list is omitted, 'dynamic' type arguments are filled in.
   InterfaceType(Class classNode, Nullability declaredNullability,
-      [List<DartType> typeArguments])
-      : this.byReference(getClassReference(classNode), declaredNullability,
+      [List<DartType>? typeArguments])
+      : this.byReference(
+            getNonNullableClassReference(classNode),
+            declaredNullability,
             typeArguments ?? _defaultTypeArguments(classNode));
 
   InterfaceType.byReference(
       this.className, this.declaredNullability, this.typeArguments)
+      // ignore: unnecessary_null_comparison
       : assert(declaredNullability != null);
 
   Class get classNode => className.asClass;
@@ -8912,7 +10701,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) {
+  bool equals(Object other, Assumptions? assumptions) {
     if (identical(this, other)) return true;
     if (other is InterfaceType) {
       if (nullability != other.nullability) return false;
@@ -8972,24 +10761,26 @@
   final Nullability declaredNullability;
 
   /// The [Typedef] this function type is created for.
-  final TypedefType typedefType;
+  final TypedefType? typedefType;
 
   final DartType returnType;
-  int _hashCode;
+
+  @override
+  late final int hashCode = _computeHashCode();
 
   FunctionType(List<DartType> positionalParameters, this.returnType,
       this.declaredNullability,
       {this.namedParameters: const <NamedType>[],
       this.typeParameters: const <TypeParameter>[],
-      int requiredParameterCount,
+      int? requiredParameterCount,
       this.typedefType})
       : this.positionalParameters = positionalParameters,
         this.requiredParameterCount =
             requiredParameterCount ?? positionalParameters.length;
 
-  Reference get typedefReference => typedefType?.typedefReference;
+  Reference? get typedefReference => typedefType?.typedefReference;
 
-  Typedef get typedef => typedefReference?.asTypedef;
+  Typedef? get typedef => typedefReference?.asTypedef;
 
   @override
   Nullability get nullability => declaredNullability;
@@ -9014,7 +10805,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) {
+  bool equals(Object other, Assumptions? assumptions) {
     if (identical(this, other)) {
       return true;
     } else if (other is FunctionType) {
@@ -9033,8 +10824,8 @@
         }
         for (int index = 0; index < typeParameters.length; index++) {
           if (!typeParameters[index]
-              .bound
-              .equals(other.typeParameters[index].bound, assumptions)) {
+              .bound!
+              .equals(other.typeParameters[index].bound!, assumptions)) {
             return false;
           }
         }
@@ -9057,8 +10848,8 @@
       }
       if (typeParameters.isNotEmpty) {
         for (int index = 0; index < typeParameters.length; index++) {
-          assumptions.forget(
-              typeParameters[index], other.typeParameters[index]);
+          assumptions!
+              .forget(typeParameters[index], other.typeParameters[index]);
         }
       }
       return true;
@@ -9083,7 +10874,7 @@
   /// Looks up the type of the named parameter with the given name.
   ///
   /// Returns `null` if there is no named parameter with the given name.
-  DartType getNamedParameter(String name) {
+  DartType? getNamedParameter(String name) {
     int lower = 0;
     int upper = namedParameters.length - 1;
     while (lower <= upper) {
@@ -9101,9 +10892,6 @@
     return null;
   }
 
-  @override
-  int get hashCode => _hashCode ??= _computeHashCode();
-
   int _computeHashCode() {
     int hash = 1237;
     hash = 0x3fffffff & (hash * 31 + requiredParameterCount);
@@ -9186,7 +10974,7 @@
   final List<DartType> typeArguments;
 
   TypedefType(Typedef typedefNode, Nullability nullability,
-      [List<DartType> typeArguments])
+      [List<DartType>? typeArguments])
       : this.byReference(typedefNode.reference, nullability,
             typeArguments ?? const <DartType>[]);
 
@@ -9216,7 +11004,7 @@
   @override
   DartType get unaliasOnce {
     DartType result =
-        Substitution.fromTypedefType(this).substituteType(typedefNode.type);
+        Substitution.fromTypedefType(this).substituteType(typedefNode.type!);
     return result.withDeclaredNullability(
         combineNullabilitiesForSubstitution(result.nullability, nullability));
   }
@@ -9230,7 +11018,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) {
+  bool equals(Object other, Assumptions? assumptions) {
     if (identical(this, other)) {
       return true;
     } else if (other is TypedefType) {
@@ -9311,7 +11099,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) {
+  bool equals(Object other, Assumptions? assumptions) {
     if (identical(this, other)) return true;
     if (other is FutureOrType) {
       if (declaredNullability != other.declaredNullability) return false;
@@ -9369,7 +11157,7 @@
   @override
   bool operator ==(Object other) => equals(other, null);
 
-  bool equals(Object other, Assumptions assumptions) {
+  bool equals(Object other, Assumptions? assumptions) {
     return other is NamedType &&
         name == other.name &&
         isRequired == other.isRequired &&
@@ -9435,10 +11223,11 @@
   ///
   /// 'null' indicates that the type parameter's bound has not been promoted and
   /// is therefore the same as the bound of [parameter].
-  DartType promotedBound;
+  DartType? promotedBound;
 
   TypeParameterType.internal(
-      this.parameter, this.declaredNullability, this.promotedBound) {
+      this.parameter, this.declaredNullability, DartType? promotedBound)
+      : this.promotedBound = promotedBound {
     assert(
         promotedBound == null ||
             (declaredNullability == Nullability.nonNullable &&
@@ -9512,7 +11301,7 @@
   }
 
   TypeParameterType(TypeParameter parameter, Nullability declaredNullability,
-      [DartType promotedBound])
+      [DartType? promotedBound])
       : this.internal(parameter, declaredNullability, promotedBound);
 
   /// Creates an intersection type between a type parameter and [promotedBound].
@@ -9539,11 +11328,10 @@
   /// `Nullability.undetermined` will be used, depending on the nullability of
   /// the bound of [parameter].
   TypeParameterType.withDefaultNullabilityForLibrary(
-      this.parameter, Library library) {
-    declaredNullability = library.isNonNullableByDefault
-        ? computeNullabilityFromBound(parameter)
-        : Nullability.legacy;
-  }
+      this.parameter, Library library)
+      : declaredNullability = library.isNonNullableByDefault
+            ? computeNullabilityFromBound(parameter)
+            : Nullability.legacy;
 
   @override
   R accept<R>(DartTypeVisitor<R> v) => v.visitTypeParameterType(this);
@@ -9559,7 +11347,7 @@
   bool operator ==(Object other) => equals(other, null);
 
   @override
-  bool equals(Object other, Assumptions assumptions) {
+  bool equals(Object other, Assumptions? assumptions) {
     if (identical(this, other)) {
       return true;
     } else if (other is TypeParameterType) {
@@ -9579,7 +11367,7 @@
       }
       if (promotedBound != null) {
         if (other.promotedBound == null) return false;
-        if (!promotedBound.equals(other.promotedBound, assumptions)) {
+        if (!promotedBound!.equals(other.promotedBound!, assumptions)) {
           return false;
         }
       } else if (other.promotedBound != null) {
@@ -9604,7 +11392,7 @@
   }
 
   /// Returns the bound of the type parameter, accounting for promotions.
-  DartType get bound => promotedBound ?? parameter.bound;
+  DartType get bound => (promotedBound ?? parameter.bound)!;
 
   /// Nullability of the type, calculated from its parts.
   ///
@@ -9627,9 +11415,7 @@
   ///     }
   @override
   Nullability get nullability {
-    return getNullability(
-        declaredNullability ?? computeNullabilityFromBound(parameter),
-        promotedBound);
+    return getNullability(declaredNullability, promotedBound);
   }
 
   /// Gets a new [TypeParameterType] with given [typeParameterTypeNullability].
@@ -9659,7 +11445,7 @@
     // non-nullable types can be passed in for the type parameter, making the
     // corresponding type parameter types 'undetermined.'  Otherwise, the
     // nullability matches that of the bound.
-    DartType bound = typeParameter.bound;
+    DartType? bound = typeParameter.bound;
     if (bound == null) {
       throw new StateError("Can't compute nullability from an absent bound.");
     }
@@ -9670,9 +11456,9 @@
     // other ways for such a dependency to exist, they should be checked here.
     bool nullabilityDependsOnItself = false;
     {
-      DartType type = typeParameter.bound;
+      DartType? type = typeParameter.bound;
       while (type is FutureOrType) {
-        type = (type as FutureOrType).typeArgument;
+        type = type.typeArgument;
       }
       if (type is TypeParameterType && type.parameter == typeParameter) {
         // Intersection types can't appear in the bound.
@@ -9701,7 +11487,7 @@
   /// is null), the nullability of the intersection type is simply
   /// [typeParameterTypeNullability].
   static Nullability getNullability(
-      Nullability typeParameterTypeNullability, DartType promotedBound) {
+      Nullability typeParameterTypeNullability, DartType? promotedBound) {
     // If promotedBound is null, getNullability simply returns the nullability
     // of the type parameter type.
     Nullability lhsNullability = typeParameterTypeNullability;
@@ -9872,7 +11658,7 @@
       printer.writeTypeParameterName(parameter);
       printer.write(nullabilityToString(declaredNullability));
       printer.write(" & ");
-      printer.writeType(promotedBound);
+      printer.writeType(promotedBound!);
       printer.write(')');
       printer.write(nullabilityToString(nullability));
     } else {
@@ -10006,20 +11792,22 @@
   /// annotations if needed.
   List<Expression> annotations = const <Expression>[];
 
-  String name; // Cosmetic name.
+  String? name; // Cosmetic name.
 
   /// The bound on the type variable.
   ///
   /// Should not be null except temporarily during IR construction.  Should
   /// be set to the root class for type parameters without an explicit bound.
-  DartType bound;
+  // TODO(johnniwinther): Can we make this late non-nullable?
+  DartType? bound;
 
   /// The default value of the type variable. It is used to provide the
   /// corresponding missing type argument in type annotations and as the
   /// fall-back type value in type inference at compile time. At run time,
   /// [defaultType] is used by the backends in place of the missing type
   /// argument of a dynamic invocation of a generic function.
-  DartType defaultType;
+  // TODO(johnniwinther): Can we make this late non-nullable?
+  DartType? defaultType;
 
   /// Describes variance of the type parameter w.r.t. declaration on which it is
   /// defined. For classes, if variance is not explicitly set, the type
@@ -10027,11 +11815,11 @@
   /// on the lattice is equivalent to [Variance.covariant]. For typedefs, it's
   /// the variance of the type parameters in the type term on the r.h.s. of the
   /// typedef.
-  int _variance;
+  int? _variance;
 
   int get variance => _variance ?? Variance.covariant;
 
-  void set variance(int newVariance) => _variance = newVariance;
+  void set variance(int? newVariance) => _variance = newVariance;
 
   bool get isLegacyCovariant => _variance == null;
 
@@ -10063,24 +11851,55 @@
     annotations.add(annotation..parent = this);
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitTypeParameter(this);
 
-  visitChildren(Visitor v) {
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
+      v.visitTypeParameter(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(annotations, v);
-    bound.accept(v);
+    bound?.accept(v);
     defaultType?.accept(v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(annotations, v, this);
-    bound = v.visitDartType(bound);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(annotations, this);
+    if (bound != null) {
+      bound = v.visitDartType(bound!);
+    }
     if (defaultType != null) {
-      defaultType = v.visitDartType(defaultType);
+      defaultType = v.visitDartType(defaultType!);
+    }
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformExpressionList(annotations, this);
+    if (bound != null) {
+      DartType newBound = v.visitDartType(bound!, dummyDartType);
+      if (identical(newBound, dummyDartType)) {
+        bound = null;
+      } else {
+        bound = newBound;
+      }
+    }
+    if (defaultType != null) {
+      DartType newDefaultType = v.visitDartType(defaultType!, dummyDartType);
+      if (identical(newDefaultType, dummyDartType)) {
+        defaultType = null;
+      } else {
+        defaultType = newDefaultType;
+      }
     }
   }
 
   /// Returns a possibly synthesized name for this type parameter, consistent
   /// with the names used across all [toString] calls.
+  @override
   String toString() {
     return "TypeParameter(${toStringInternal()})";
   }
@@ -10098,7 +11917,8 @@
   final List<DartType> typeArguments;
 
   Supertype(Class classNode, List<DartType> typeArguments)
-      : this.byReference(getClassReference(classNode), typeArguments);
+      : this.byReference(
+            getNonNullableClassReference(classNode), typeArguments);
 
   Supertype.byReference(this.className, this.typeArguments);
 
@@ -10273,6 +12093,7 @@
 
 class StringConstant extends PrimitiveConstant<String> {
   StringConstant(String value) : super(value) {
+    // ignore: unnecessary_null_comparison
     assert(value != null);
   }
 
@@ -10322,6 +12143,7 @@
   @override
   void toTextInternal(AstPrinter printer) {
     printer.write('#');
+    // ignore: unnecessary_null_comparison
     if (printer.includeAuxiliaryProperties && libraryReference != null) {
       printer.write(libraryNameToString(libraryReference.asLibrary));
       printer.write('::');
@@ -10368,11 +12190,9 @@
   @override
   String toString() => 'MapConstant(${toStringInternal()})';
 
-  int _cachedHashCode;
-  int get hashCode {
-    return _cachedHashCode ??= _Hash.combine2Finish(
-        keyType.hashCode, valueType.hashCode, _Hash.combineListHash(entries));
-  }
+  @override
+  late final int hashCode = _Hash.combine2Finish(
+      keyType.hashCode, valueType.hashCode, _Hash.combineListHash(entries));
 
   bool operator ==(Object other) =>
       identical(this, other) ||
@@ -10448,11 +12268,9 @@
   @override
   String toString() => 'ListConstant(${toStringInternal()})';
 
-  int _cachedHashCode;
-  int get hashCode {
-    return _cachedHashCode ??= _Hash.combineFinish(
-        typeArgument.hashCode, _Hash.combineListHash(entries));
-  }
+  @override
+  late final int hashCode = _Hash.combineFinish(
+      typeArgument.hashCode, _Hash.combineListHash(entries));
 
   bool operator ==(Object other) =>
       identical(this, other) ||
@@ -10497,11 +12315,9 @@
   @override
   String toString() => 'SetConstant(${toStringInternal()})';
 
-  int _cachedHashCode;
-  int get hashCode {
-    return _cachedHashCode ??= _Hash.combineFinish(
-        typeArgument.hashCode, _Hash.combineListHash(entries));
-  }
+  @override
+  late final int hashCode = _Hash.combineFinish(
+      typeArgument.hashCode, _Hash.combineListHash(entries));
 
   bool operator ==(Object other) =>
       identical(this, other) ||
@@ -10556,13 +12372,9 @@
   @override
   String toString() => 'InstanceConstant(${toStringInternal()})';
 
-  int _cachedHashCode;
-  int get hashCode {
-    return _cachedHashCode ??= _Hash.combine2Finish(
-        classReference.hashCode,
-        listHashCode(typeArguments),
-        _Hash.combineMapHashUnordered(fieldValues));
-  }
+  @override
+  late final int hashCode = _Hash.combine2Finish(classReference.hashCode,
+      listHashCode(typeArguments), _Hash.combineMapHashUnordered(fieldValues));
 
   bool operator ==(Object other) {
     return identical(this, other) ||
@@ -10630,7 +12442,7 @@
 
   TearOffConstant.byReference(this.procedureReference);
 
-  Procedure get procedure => procedureReference?.asProcedure;
+  Procedure get procedure => procedureReference.asProcedure;
 
   visitChildren(Visitor v) {
     procedureReference.asProcedure.acceptReference(v);
@@ -10655,7 +12467,7 @@
   }
 
   FunctionType getType(StaticTypeContext context) {
-    return procedure.function.computeFunctionType(context.nonNullable);
+    return procedure.function!.computeFunctionType(context.nonNullable);
   }
 }
 
@@ -10694,7 +12506,7 @@
   final Expression expression;
 
   UnevaluatedConstant(this.expression) {
-    expression?.parent = null;
+    expression.parent = null;
   }
 
   visitChildren(Visitor v) {
@@ -10744,7 +12556,7 @@
   ///
   /// Note that this field can be null, and by convention should be null if the
   /// list is empty.
-  List<String> problemsAsJson;
+  List<String>? problemsAsJson;
 
   final List<Library> libraries;
 
@@ -10759,19 +12571,19 @@
       <String, MetadataRepository<dynamic>>{};
 
   /// Reference to the main method in one of the libraries.
-  Reference _mainMethodName;
-  Reference get mainMethodName => _mainMethodName;
-  NonNullableByDefaultCompiledMode _mode;
+  Reference? _mainMethodName;
+  Reference? get mainMethodName => _mainMethodName;
+  NonNullableByDefaultCompiledMode? _mode;
   NonNullableByDefaultCompiledMode get mode {
     return _mode ?? NonNullableByDefaultCompiledMode.Weak;
   }
 
-  NonNullableByDefaultCompiledMode get modeRaw => _mode;
+  NonNullableByDefaultCompiledMode? get modeRaw => _mode;
 
   Component(
-      {CanonicalName nameRoot,
-      List<Library> libraries,
-      Map<Uri, Source> uriToSource})
+      {CanonicalName? nameRoot,
+      List<Library>? libraries,
+      Map<Uri, Source>? uriToSource})
       : root = nameRoot ?? new CanonicalName.root(),
         libraries = libraries ?? <Library>[],
         uriToSource = uriToSource ?? <Uri, Source>{} {
@@ -10779,13 +12591,14 @@
   }
 
   void adoptChildren() {
+    // ignore: unnecessary_null_comparison
     if (libraries != null) {
       for (int i = 0; i < libraries.length; ++i) {
         // The libraries are owned by this component, and so are their canonical
         // names if they exist.
         Library library = libraries[i];
         library.parent = this;
-        CanonicalName name = library.reference.canonicalName;
+        CanonicalName? name = library.reference.canonicalName;
         if (name != null && name.parent != root) {
           root.adoptChild(name);
         }
@@ -10848,7 +12661,7 @@
     root.unbindAll();
   }
 
-  Procedure get mainMethod => mainMethodName?.asProcedure;
+  Procedure? get mainMethod => mainMethodName?.asProcedure;
 
   void setMainMethodAndMode(Reference main, bool overwriteMainIfSet,
       NonNullableByDefaultCompiledMode mode) {
@@ -10858,21 +12671,33 @@
     _mode = mode;
   }
 
+  @override
   R accept<R>(TreeVisitor<R> v) => v.visitComponent(this);
 
-  visitChildren(Visitor v) {
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitComponent(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
     visitList(libraries, v);
     mainMethod?.acceptReference(v);
   }
 
-  transformChildren(Transformer v) {
-    transformList(libraries, v, this);
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(libraries, this);
   }
 
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformLibraryList(libraries, this);
+  }
+
+  @override
   Component get enclosingComponent => this;
 
   /// Translates an offset to line and column numbers in the given file.
-  Location getLocation(Uri file, int offset) {
+  Location? getLocation(Uri? file, int offset) {
     return uriToSource[file]?.getLocation(file, offset);
   }
 
@@ -10905,7 +12730,8 @@
 /// A tuple with file, line, and column number, for displaying human-readable
 /// locations.
 class Location {
-  final Uri file;
+  // TODO(johnniwinther): Make this non-nullable.
+  final Uri? file;
   final int line; // 1-based.
   final int column; // 1-based.
 
@@ -11030,49 +12856,6 @@
   }
 }
 
-void transformTypeList(List<DartType> nodes, Transformer visitor) {
-  int storeIndex = 0;
-  for (int i = 0; i < nodes.length; ++i) {
-    DartType result = visitor.visitDartType(nodes[i]);
-    if (result != null) {
-      nodes[storeIndex] = result;
-      ++storeIndex;
-    }
-  }
-  if (storeIndex < nodes.length) {
-    nodes.length = storeIndex;
-  }
-}
-
-void transformSupertypeList(List<Supertype> nodes, Transformer visitor) {
-  int storeIndex = 0;
-  for (int i = 0; i < nodes.length; ++i) {
-    Supertype result = visitor.visitSupertype(nodes[i]);
-    if (result != null) {
-      nodes[storeIndex] = result;
-      ++storeIndex;
-    }
-  }
-  if (storeIndex < nodes.length) {
-    nodes.length = storeIndex;
-  }
-}
-
-void transformList(List<TreeNode> nodes, Transformer visitor, TreeNode parent) {
-  int storeIndex = 0;
-  for (int i = 0; i < nodes.length; ++i) {
-    TreeNode result = nodes[i].accept(visitor);
-    if (result != null) {
-      nodes[storeIndex] = result;
-      result.parent = parent;
-      ++storeIndex;
-    }
-  }
-  if (storeIndex < nodes.length) {
-    nodes.length = storeIndex;
-  }
-}
-
 class _ChildReplacer extends Transformer {
   final TreeNode child;
   final TreeNode replacement;
@@ -11080,7 +12863,7 @@
   _ChildReplacer(this.child, this.replacement);
 
   @override
-  defaultTreeNode(TreeNode node) {
+  TreeNode defaultTreeNode(TreeNode node) {
     if (node == child) {
       return replacement;
     } else {
@@ -11090,31 +12873,35 @@
 }
 
 class Source {
-  final List<int> lineStarts;
+  final List<int>? lineStarts;
 
   /// A UTF8 encoding of the original source file.
-  final List<int> source;
+  final List<int>? source;
 
   final Uri importUri;
 
   final Uri fileUri;
 
-  Set<Reference> constantCoverageConstructors;
+  Set<Reference>? constantCoverageConstructors;
 
-  String cachedText;
+  String? cachedText;
 
   Source(this.lineStarts, this.source, this.importUri, this.fileUri);
 
   /// Return the text corresponding to [line] which is a 1-based line
   /// number. The returned line contains no line separators.
-  String getTextLine(int line) {
+  String? getTextLine(int line) {
+    List<int>? lineStarts = this.lineStarts;
     if (source == null ||
-        source.isEmpty ||
+        source!.isEmpty ||
         lineStarts == null ||
-        lineStarts.isEmpty) return null;
+        lineStarts.isEmpty) {
+      return null;
+    }
     RangeError.checkValueInInterval(line, 1, lineStarts.length, 'line');
 
-    cachedText ??= utf8.decode(source, allowMalformed: true);
+    String cachedText =
+        this.cachedText ??= utf8.decode(source!, allowMalformed: true);
     // -1 as line numbers start at 1.
     int index = line - 1;
     if (index + 1 == lineStarts.length) {
@@ -11135,7 +12922,8 @@
   }
 
   /// Translates an offset to 1-based line and column numbers in the given file.
-  Location getLocation(Uri file, int offset) {
+  Location getLocation(Uri? file, int offset) {
+    List<int>? lineStarts = this.lineStarts;
     if (lineStarts == null || lineStarts.isEmpty) {
       return new Location(file, TreeNode.noOffset, TreeNode.noOffset);
     }
@@ -11163,6 +12951,7 @@
   /// has no lines.
   /// Throws [RangeError] if line or calculated offset are out of range.
   int getOffset(int line, int column) {
+    List<int>? lineStarts = this.lineStarts;
     if (lineStarts == null || lineStarts.isEmpty) {
       return -1;
     }
@@ -11177,11 +12966,11 @@
 /// ProcedureKind.
 ///
 /// Returns `null` if the member is `null`.
-Reference getMemberReferenceBasedOnProcedureKind(
-    Member member, ProcedureKind kind) {
+Reference? getMemberReferenceBasedOnProcedureKind(
+    Member? member, ProcedureKind kind) {
   if (member == null) return null;
   if (member is Field) {
-    if (kind == ProcedureKind.Setter) return member.setterReference;
+    if (kind == ProcedureKind.Setter) return member.setterReference!;
     return member.getterReference;
   }
   return member.reference;
@@ -11191,8 +12980,12 @@
 ///
 /// Returns `null` if the member is `null`.
 /// TODO(jensj): Should it be called NotSetter instead of Getter?
-Reference getMemberReferenceGetter(Member member) {
+Reference? getMemberReferenceGetter(Member? member) {
   if (member == null) return null;
+  return getNonNullableMemberReferenceGetter(member);
+}
+
+Reference getNonNullableMemberReferenceGetter(Member member) {
   if (member is Field) return member.getterReference;
   return member.reference;
 }
@@ -11200,26 +12993,35 @@
 /// Returns the setter [Reference] object for the given member.
 ///
 /// Returns `null` if the member is `null`.
-Reference getMemberReferenceSetter(Member member) {
+Reference? getMemberReferenceSetter(Member? member) {
   if (member == null) return null;
-  if (member is Field) return member.setterReference;
+  return getNonNullableMemberReferenceSetter(member);
+}
+
+Reference getNonNullableMemberReferenceSetter(Member member) {
+  if (member is Field) return member.setterReference!;
   return member.reference;
 }
 
 /// Returns the [Reference] object for the given class.
 ///
 /// Returns `null` if the class is `null`.
-Reference getClassReference(Class class_) {
+Reference? getClassReference(Class? class_) {
   return class_?.reference;
 }
 
+/// Returns the [Reference] object for the given class.
+Reference getNonNullableClassReference(Class class_) {
+  return class_.reference;
+}
+
 /// Returns the canonical name of [member], or throws an exception if the
 /// member has not been assigned a canonical name yet.
 ///
 /// Returns `null` if the member is `null`.
-CanonicalName getCanonicalNameOfMemberGetter(Member member) {
+CanonicalName? getCanonicalNameOfMemberGetter(Member? member) {
   if (member == null) return null;
-  CanonicalName canonicalName;
+  CanonicalName? canonicalName;
   if (member is Field) {
     canonicalName = member.getterCanonicalName;
   } else {
@@ -11235,9 +13037,9 @@
 /// member has not been assigned a canonical name yet.
 ///
 /// Returns `null` if the member is `null`.
-CanonicalName getCanonicalNameOfMemberSetter(Member member) {
+CanonicalName? getCanonicalNameOfMemberSetter(Member? member) {
   if (member == null) return null;
-  CanonicalName canonicalName;
+  CanonicalName? canonicalName;
   if (member is Field) {
     canonicalName = member.setterCanonicalName;
   } else {
@@ -11253,7 +13055,7 @@
 /// class has not been assigned a canonical name yet.
 ///
 /// Returns `null` if the class is `null`.
-CanonicalName getCanonicalNameOfClass(Class class_) {
+CanonicalName? getCanonicalNameOfClass(Class? class_) {
   if (class_ == null) return null;
   if (class_.canonicalName == null) {
     throw '$class_ has no canonical name';
@@ -11265,7 +13067,7 @@
 /// class has not been assigned a canonical name yet.
 ///
 /// Returns `null` if the extension is `null`.
-CanonicalName getCanonicalNameOfExtension(Extension extension) {
+CanonicalName? getCanonicalNameOfExtension(Extension? extension) {
   if (extension == null) return null;
   if (extension.canonicalName == null) {
     throw '$extension has no canonical name';
@@ -11277,7 +13079,7 @@
 /// library has not been assigned a canonical name yet.
 ///
 /// Returns `null` if the library is `null`.
-CanonicalName getCanonicalNameOfLibrary(Library library) {
+CanonicalName? getCanonicalNameOfLibrary(Library? library) {
   if (library == null) return null;
   if (library.canonicalName == null) {
     throw '$library has no canonical name';
@@ -11356,9 +13158,12 @@
     return hash;
   }
 
-  static int combineMapHashUnordered(Map map, [int hash = 2]) {
+  static int combineMapHashUnordered(Map? map, [int hash = 2]) {
     if (map == null || map.isEmpty) return hash;
-    List<int> entryHashes = List.filled(map.length, null);
+    List<int> entryHashes = List.filled(
+        map.length,
+        // `-1` is used as a dummy default value.
+        -1);
     int i = 0;
     for (core.MapEntry entry in map.entries) {
       entryHashes[i++] = combine(entry.key.hashCode, entry.value.hashCode);
@@ -11375,7 +13180,7 @@
   }
 }
 
-int listHashCode(List list) {
+int listHashCode(List<Object> list) {
   return _Hash.finish(_Hash.combineListHash(list));
 }
 
@@ -11417,7 +13222,7 @@
 /// typedef has not been assigned a canonical name yet.
 ///
 /// Returns `null` if the typedef is `null`.
-CanonicalName getCanonicalNameOfTypedef(Typedef typedef_) {
+CanonicalName? getCanonicalNameOfTypedef(Typedef? typedef_) {
   if (typedef_ == null) return null;
   if (typedef_.canonicalName == null) {
     throw '$typedef_ has no canonical name';
@@ -11430,7 +13235,8 @@
 /// static analysis and runtime behavior of the library are unaffected.
 const Null informative = null;
 
-Location _getLocationInComponent(Component component, Uri fileUri, int offset) {
+Location? _getLocationInComponent(
+    Component? component, Uri? fileUri, int offset) {
   if (component != null) {
     return component.getLocation(fileUri, offset);
   } else {
@@ -11471,13 +13277,11 @@
 List<DartType> getAsTypeArguments(
     List<TypeParameter> typeParameters, Library library) {
   if (typeParameters.isEmpty) return const <DartType>[];
-  List<DartType> result =
-      new List<DartType>.filled(typeParameters.length, null, growable: false);
-  for (int i = 0; i < result.length; ++i) {
-    result[i] = new TypeParameterType.withDefaultNullabilityForLibrary(
-        typeParameters[i], library);
-  }
-  return result;
+  return new List<DartType>.generate(
+      typeParameters.length,
+      (int i) => new TypeParameterType.withDefaultNullabilityForLibrary(
+          typeParameters[i], library),
+      growable: false);
 }
 
 class Version extends Object {
@@ -11485,7 +13289,9 @@
   final int minor;
 
   const Version(this.major, this.minor)
+      // ignore: unnecessary_null_comparison
       : assert(major != null),
+        // ignore: unnecessary_null_comparison
         assert(minor != null);
 
   bool operator <(Version other) {
@@ -11544,15 +13350,218 @@
   }
 }
 
-/// Non-nullable `DartType` value to be used as a dummy initial value for the
-/// `List.filled` constructor.
-const DartType dartTypeDummy = const DynamicType();
+/// Non-nullable [DartType] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final DartType dummyDartType = new DynamicType();
 
-/// Non-nullable `NamedType` value to be used as a dummy initial value for the
-/// `List.filled` constructor.
-const NamedType namedTypeDummy =
-    const NamedType('', dartTypeDummy, isRequired: false);
+/// Non-nullable [Supertype] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Supertype dummySupertype = new Supertype(dummyClass, const []);
 
-/// Non-nullable `Member` value to be used as a dummy initial value for the
+/// Non-nullable [NamedType] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final NamedType dummyNamedType =
+    new NamedType('', dummyDartType, isRequired: false);
+
+/// Non-nullable [Uri] dummy value.
+final Uri dummyUri = new Uri(scheme: 'dummy');
+
+/// Non-nullable [Name] dummy value.
+final Name dummyName = new _PublicName('');
+
+/// Non-nullable [Library] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Library dummyLibrary = new Library(dummyUri);
+
+/// Non-nullable [LibraryDependency] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final LibraryDependency dummyLibraryDependency =
+    new LibraryDependency.import(dummyLibrary);
+
+/// Non-nullable [Combinator] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Combinator dummyCombinator = new Combinator(false, const []);
+
+/// Non-nullable [LibraryPart] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final LibraryPart dummyLibraryPart = new LibraryPart(const [], '');
+
+/// Non-nullable [Class] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Class dummyClass = new Class();
+
+/// Non-nullable [Constructor] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Constructor dummyConstructor = new Constructor(dummyFunctionNode);
+
+/// Non-nullable [Extension] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Extension dummyExtension = new Extension();
+
+/// Non-nullable [Member] dummy value.
+///
+/// This can be used for instance as a dummy initial value for the
 /// `List.filled` constructor.
 final Member dummyMember = new Field.mutable(new _PublicName(''));
+
+/// Non-nullable [Procedure] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Procedure dummyProcedure =
+    new Procedure(dummyName, ProcedureKind.Method, dummyFunctionNode);
+
+/// Non-nullable [Field] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Field dummyField = new Field.mutable(dummyName);
+
+/// Non-nullable [RedirectingFactoryConstructor] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final RedirectingFactoryConstructor dummyRedirectingFactoryConstructor =
+    new RedirectingFactoryConstructor(null);
+
+/// Non-nullable [Typedef] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Typedef dummyTypedef = new Typedef('', null);
+
+/// Non-nullable [Initializer] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Initializer dummyInitializer = new InvalidInitializer();
+
+/// Non-nullable [FunctionNode] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final FunctionNode dummyFunctionNode = new FunctionNode(null);
+
+/// Non-nullable [Statement] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Statement dummyStatement = new EmptyStatement();
+
+/// Non-nullable [Expression] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Expression dummyExpression = new NullLiteral();
+
+/// Non-nullable [NamedExpression] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final NamedExpression dummyNamedExpression =
+    new NamedExpression('', dummyExpression);
+
+/// Non-nullable [VariableDeclaration] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final VariableDeclaration dummyVariableDeclaration =
+    new VariableDeclaration(null);
+
+/// Non-nullable [TypeParameter] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final TypeParameter dummyTypeParameter = new TypeParameter();
+
+/// Non-nullable [MapEntry] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final MapEntry dummyMapEntry = new MapEntry(dummyExpression, dummyExpression);
+
+/// Non-nullable [Arguments] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Arguments dummyArguments = new Arguments(const []);
+
+/// Non-nullable [AssertStatement] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final AssertStatement dummyAssertStatement = new AssertStatement(
+    dummyExpression,
+    conditionStartOffset: TreeNode.noOffset,
+    conditionEndOffset: TreeNode.noOffset);
+
+/// Non-nullable [SwitchCase] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final SwitchCase dummySwitchCase = new SwitchCase.empty();
+
+/// Non-nullable [Catch] dummy value.
+///
+/// This is used as the removal sentinel in [RemovingTransformer] and can be
+/// used for instance as a dummy initial value for the `List.filled`
+/// constructor.
+final Catch dummyCatch = new Catch(null, dummyStatement);
+
+/// Sentinel value used to signal that a node cannot be removed through the
+/// [RemovingTransformer].
+const Null cannotRemoveSentinel = null;
+
+/// Helper that can be used in asserts to check that [list] is mutable by
+/// adding and removing [dummyElement].
+bool checkListIsMutable<E>(List<E> list, E dummyElement) {
+  list
+    ..add(dummyElement)
+    ..removeLast();
+  return true;
+}
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 7eb93df..f6ae627 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -6,7 +6,6 @@
 
 library kernel.ast_from_binary;
 
-import 'dart:core' hide MapEntry;
 import 'dart:developer';
 import 'dart:convert';
 import 'dart:typed_data';
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 821b2f9..bed4058 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -6,7 +6,6 @@
 
 library kernel.ast_to_binary;
 
-import 'dart:core' hide MapEntry;
 import 'dart:convert';
 import 'dart:developer';
 import 'dart:io' show BytesBuilder;
diff --git a/pkg/kernel/lib/canonical_name.dart b/pkg/kernel/lib/canonical_name.dart
index 70f3004..af7344e 100644
--- a/pkg/kernel/lib/canonical_name.dart
+++ b/pkg/kernel/lib/canonical_name.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.
 
-// @dart = 2.9
-
 library kernel.canonical_name;
 
 import 'ast.dart';
@@ -69,25 +67,27 @@
 /// The "qualified name" allows a member to have a name that is private to
 /// a library other than the one containing that member.
 class CanonicalName {
-  CanonicalName _parent;
+  CanonicalName? _parent;
 
-  CanonicalName get parent => _parent;
+  CanonicalName? get parent => _parent;
 
   final String name;
-  CanonicalName _nonRootTop;
+  CanonicalName? _nonRootTop;
 
-  Map<String, CanonicalName> _children;
+  Map<String, CanonicalName>? _children;
 
   /// The library, class, or member bound to this name.
-  Reference reference;
+  Reference? reference;
 
   /// Temporary index used during serialization.
   int index = -1;
 
-  CanonicalName._(this._parent, this.name) {
+  CanonicalName._(CanonicalName parent, this.name) : _parent = parent {
+    // ignore: unnecessary_null_comparison
     assert(name != null);
+    // ignore: unnecessary_null_comparison
     assert(parent != null);
-    _nonRootTop = _parent.isRoot ? this : _parent._nonRootTop;
+    _nonRootTop = parent.isRoot ? this : parent._nonRootTop;
   }
 
   CanonicalName.root()
@@ -96,15 +96,16 @@
         name = '';
 
   bool get isRoot => _parent == null;
-  CanonicalName get nonRootTop => _nonRootTop;
+
+  CanonicalName? get nonRootTop => _nonRootTop;
 
   Iterable<CanonicalName> get children =>
       _children?.values ?? const <CanonicalName>[];
 
-  Iterable<CanonicalName> get childrenOrNull => _children?.values;
+  Iterable<CanonicalName>? get childrenOrNull => _children?.values;
 
   bool hasChild(String name) {
-    return _children != null && _children.containsKey(name);
+    return _children != null && _children!.containsKey(name);
   }
 
   CanonicalName getChild(String name) {
@@ -121,32 +122,32 @@
 
   CanonicalName getChildFromQualifiedName(Name name) {
     return name.isPrivate
-        ? getChildFromUri(name.library.importUri).getChild(name.text)
+        ? getChildFromUri(name.library!.importUri).getChild(name.text)
         : getChild(name.text);
   }
 
   CanonicalName getChildFromProcedure(Procedure procedure) {
     return getChild(getProcedureQualifier(procedure))
-        .getChildFromQualifiedName(procedure.name);
+        .getChildFromQualifiedName(procedure.name!);
   }
 
   CanonicalName getChildFromField(Field field) {
-    return getChild('@fields').getChildFromQualifiedName(field.name);
+    return getChild('@fields').getChildFromQualifiedName(field.name!);
   }
 
   CanonicalName getChildFromFieldSetter(Field field) {
-    return getChild('@=fields').getChildFromQualifiedName(field.name);
+    return getChild('@=fields').getChildFromQualifiedName(field.name!);
   }
 
   CanonicalName getChildFromConstructor(Constructor constructor) {
     return getChild('@constructors')
-        .getChildFromQualifiedName(constructor.name);
+        .getChildFromQualifiedName(constructor.name!);
   }
 
   CanonicalName getChildFromRedirectingFactoryConstructor(
       RedirectingFactoryConstructor redirectingFactoryConstructor) {
     return getChild('@factories')
-        .getChildFromQualifiedName(redirectingFactoryConstructor.name);
+        .getChildFromQualifiedName(redirectingFactoryConstructor.name!);
   }
 
   CanonicalName getChildFromFieldWithName(Name name) {
@@ -175,26 +176,27 @@
   /// the same name.
   void adoptChild(CanonicalName child) {
     if (child._parent == this) return;
-    if (_children != null && _children.containsKey(child.name)) {
+    if (_children != null && _children!.containsKey(child.name)) {
       throw 'Cannot add a child to $this because this name already has a '
           'child named ${child.name}';
     }
-    child._parent.removeChild(child.name);
+    child._parent?.removeChild(child.name);
     child._parent = this;
-    if (_children == null) _children = <String, CanonicalName>{};
-    _children[child.name] = child;
+    _children ??= <String, CanonicalName>{};
+    _children![child.name] = child;
   }
 
   void removeChild(String name) {
     if (_children != null) {
-      _children.remove(name);
-      if (_children.isEmpty) {
+      _children!.remove(name);
+      if (_children!.isEmpty) {
         _children = null;
       }
     }
   }
 
   void bindTo(Reference target) {
+    // ignore: unnecessary_null_comparison
     if (target == null) {
       throw '$this cannot be bound to null';
     }
@@ -217,25 +219,25 @@
     // canonical name tree. We need to establish better invariants about the
     // state of the canonical name tree, since for instance [unbindAll] doesn't
     // remove unneeded leaf nodes.
-    _parent.removeChild(name);
+    _parent?.removeChild(name);
   }
 
   void _unbindInternal() {
     if (reference == null) return;
-    assert(reference.canonicalName == this);
-    if (reference.node is Class) {
+    assert(reference!.canonicalName == this);
+    if (reference!.node is Class) {
       // TODO(jensj): Get rid of this. This is only needed because pkg:vm does
       // weird stuff in transformations. `unbind` should probably be private.
-      Class c = reference.node;
+      Class c = reference!.asClass;
       c.ensureLoaded();
     }
-    reference.canonicalName = null;
+    reference!.canonicalName = null;
     reference = null;
   }
 
   void unbindAll() {
     _unbindInternal();
-    Iterable<CanonicalName> children_ = childrenOrNull;
+    Iterable<CanonicalName>? children_ = childrenOrNull;
     if (children_ != null) {
       for (CanonicalName child in children_) {
         child.unbindAll();
@@ -246,8 +248,8 @@
   String toString() => _parent == null ? 'root' : '$parent::$name';
   String toStringInternal() {
     if (isRoot) return "";
-    if (parent.isRoot) return "$name";
-    return "${parent.toStringInternal()}::$name";
+    if (parent!.isRoot) return "$name";
+    return "${parent!.toStringInternal()}::$name";
   }
 
   Reference getReference() {
diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart
index 08ed371..0c6e3f3 100644
--- a/pkg/kernel/lib/class_hierarchy.dart
+++ b/pkg/kernel/lib/class_hierarchy.dart
@@ -8,7 +8,6 @@
 import 'dart:math';
 import 'dart:typed_data';
 
-// ignore: import_of_legacy_library_into_null_safe
 import 'ast.dart' hide MapEntry;
 import 'core_types.dart';
 import 'type_algebra.dart';
@@ -283,7 +282,7 @@
   /// [getDeclaredMembers] and [getInterfaceMembers].
   static int compareMembers(Member first, Member second) {
     if (first == second) return 0;
-    return compareNames(first.name, second.name);
+    return compareNames(first.name!, second.name!);
   }
 
   /// Compares names, using the same sort order as [getDeclaredMembers] and
@@ -329,7 +328,7 @@
     while (low <= high) {
       int mid = low + ((high - low) >> 1);
       Member pivot = members[mid];
-      int comparison = compareNames(name, pivot.name);
+      int comparison = compareNames(name, pivot.name!);
       if (comparison < 0) {
         high = mid - 1;
       } else if (comparison > 0) {
@@ -418,9 +417,9 @@
   Member? getSingleTargetForInterfaceInvocation(Member interfaceTarget,
       {bool setter: false}) {
     if (invalidated) throw "This data structure has been invalidated";
-    Name name = interfaceTarget.name;
+    Name name = interfaceTarget.name!;
     Member? target = null;
-    ClassSet subtypes = getSubtypesOf(interfaceTarget.enclosingClass);
+    ClassSet subtypes = getSubtypesOf(interfaceTarget.enclosingClass!);
     for (Class c in subtypes) {
       if (!c.isAbstract) {
         Member? candidate =
@@ -591,8 +590,14 @@
         heap.add(infoFor(supertype.classNode));
       }
 
-      if (classNode.supertype != null) addToHeap(classNode.supertype);
-      if (classNode.mixedInType != null) addToHeap(classNode.mixedInType);
+      Supertype? supertype = classNode.supertype;
+      if (supertype != null) {
+        addToHeap(supertype);
+      }
+      Supertype? mixedInType = classNode.mixedInType;
+      if (mixedInType != null) {
+        addToHeap(mixedInType);
+      }
       classNode.implementedTypes.forEach(addToHeap);
     }
     return chain;
@@ -861,11 +866,13 @@
     void removeClass(Class cls) {
       _ClassInfo? info = _infoMap[cls];
       if (info == null) return;
-      if (cls.supertype != null) {
-        _infoMap[cls.supertype.classNode]?.directExtenders.remove(info);
+      Supertype? supertype = cls.supertype;
+      if (supertype != null) {
+        _infoMap[supertype.classNode]?.directExtenders.remove(info);
       }
-      if (cls.mixedInType != null) {
-        _infoMap[cls.mixedInType.classNode]?.directMixers.remove(info);
+      Supertype? mixedInType = cls.mixedInType;
+      if (mixedInType != null) {
+        _infoMap[mixedInType.classNode]?.directMixers.remove(info);
       }
       for (Supertype supertype in cls.implementedTypes) {
         _infoMap[supertype.classNode]?.directImplementers.remove(info);
@@ -1095,12 +1102,14 @@
       }
       _collectSupersForClass(class_);
 
-      if (class_.supertype != null) {
-        _recordSuperTypes(info, class_.supertype);
+      Supertype? supertype = class_.supertype;
+      if (supertype != null) {
+        _recordSuperTypes(info, supertype);
       }
-      if (class_.mixedInType != null) {
+      Supertype? mixedInType = class_.mixedInType;
+      if (mixedInType != null) {
         mixinInferrer?.infer(this, class_);
-        _recordSuperTypes(info, class_.mixedInType);
+        _recordSuperTypes(info, mixedInType);
       }
       for (Supertype supertype in class_.implementedTypes) {
         _recordSuperTypes(info, supertype);
@@ -1169,10 +1178,11 @@
     if (members != null) return members;
 
     List<Member> inherited;
-    if (classNode.supertype == null) {
+    Supertype? supertype = classNode.supertype;
+    if (supertype == null) {
       inherited = const <Member>[];
     } else {
-      Class superClassNode = classNode.supertype.classNode;
+      Class superClassNode = supertype.classNode;
       _ClassInfo superInfo = _infoMap[superClassNode]!;
       inherited =
           _buildImplementedMembers(superClassNode, superInfo, setters: setters);
@@ -1208,7 +1218,7 @@
           setters: setters)) {
         if (mixinMember is! Procedure ||
             (mixinMember is Procedure && !mixinMember.isSynthetic)) {
-          memberMap[mixinMember.name] = mixinMember;
+          memberMap[mixinMember.name!] = mixinMember;
         }
       }
     }
@@ -1217,21 +1227,21 @@
       if (procedure.isStatic) continue;
       if (procedure.kind == ProcedureKind.Setter) {
         if (setters) {
-          memberMap[procedure.name] = procedure;
+          memberMap[procedure.name!] = procedure;
         }
       } else {
         if (!setters) {
-          memberMap[procedure.name] = procedure;
+          memberMap[procedure.name!] = procedure;
         }
       }
     }
     for (Field field in classNode.fields) {
       if (field.isStatic) continue;
       if (!setters) {
-        memberMap[field.name] = field;
+        memberMap[field.name!] = field;
       }
       if (setters && field.hasSetter) {
-        memberMap[field.name] = field;
+        memberMap[field.name!] = field;
       }
     }
 
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index 83a94a1..979d08f 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -6,8 +6,6 @@
 
 library kernel.clone;
 
-import 'dart:core' hide MapEntry;
-
 import 'ast.dart';
 import 'type_algebra.dart';
 
diff --git a/pkg/kernel/lib/core_types.dart b/pkg/kernel/lib/core_types.dart
index 2fa52ac..edac20b 100644
--- a/pkg/kernel/lib/core_types.dart
+++ b/pkg/kernel/lib/core_types.dart
@@ -4,7 +4,6 @@
 
 library kernel.core_types;
 
-// ignore: import_of_legacy_library_into_null_safe
 import 'ast.dart';
 import 'library_index.dart';
 import 'type_algebra.dart';
@@ -1137,13 +1136,13 @@
     if (type is TypeParameterType &&
         type.promotedBound != null &&
         type.isPotentiallyNonNullable) {
-      return isBottom(type.promotedBound);
+      return isBottom(type.promotedBound!);
     }
 
     // BOTTOM(X extends T) is true iff BOTTOM(T).
     if (type is TypeParameterType && type.isPotentiallyNonNullable) {
       assert(type.promotedBound == null);
-      return isBottom(type.parameter.bound);
+      return isBottom(type.parameter.bound!);
     }
 
     if (type is BottomType) return true;
diff --git a/pkg/kernel/lib/default_language_version.dart b/pkg/kernel/lib/default_language_version.dart
index 5b39ec4..6de3073 100644
--- a/pkg/kernel/lib/default_language_version.dart
+++ b/pkg/kernel/lib/default_language_version.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.
 
-// @dart = 2.9
-
 // NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
 //
 // Instead modify 'tools/experimental_features.yaml' and run
diff --git a/pkg/kernel/lib/import_table.dart b/pkg/kernel/lib/import_table.dart
index 1cc27c2..d6bf7ee 100644
--- a/pkg/kernel/lib/import_table.dart
+++ b/pkg/kernel/lib/import_table.dart
@@ -4,7 +4,6 @@
 
 library kernel.import_table;
 
-// ignore: import_of_legacy_library_into_null_safe
 import 'ast.dart';
 
 abstract class ImportTable {
@@ -111,7 +110,7 @@
   visitLibrary(Library node) {
     super.visitLibrary(node);
     for (Reference exportedReference in node.additionalExports) {
-      addLibraryImport(exportedReference.node.parent as Library);
+      addLibraryImport(exportedReference.node!.parent as Library);
     }
   }
 
diff --git a/pkg/kernel/lib/library_index.dart b/pkg/kernel/lib/library_index.dart
index 630763d..2619b62 100644
--- a/pkg/kernel/lib/library_index.dart
+++ b/pkg/kernel/lib/library_index.dart
@@ -4,7 +4,6 @@
 
 library kernel.library_index;
 
-// ignore: import_of_legacy_library_into_null_safe
 import 'ast.dart';
 
 /// Provides name-based access to library, class, and member AST nodes.
@@ -142,18 +141,18 @@
       _classes = <String, _MemberTable>{};
       _classes![LibraryIndex.topLevel] = new _MemberTable.topLevel(this);
       for (Class class_ in library.classes) {
-        _classes![class_.name] = new _MemberTable.fromClass(this, class_);
+        _classes![class_.name!] = new _MemberTable.fromClass(this, class_);
       }
       for (Extension extension_ in library.extensions) {
-        _classes![extension_.name] =
+        _classes![extension_.name!] =
             new _MemberTable.fromExtension(this, extension_);
       }
       for (Reference reference in library.additionalExports) {
-        NamedNode node = reference.node;
+        NamedNode? node = reference.node;
         if (node is Class) {
-          _classes![node.name] = new _MemberTable.fromClass(this, node);
+          _classes![node.name!] = new _MemberTable.fromClass(this, node);
         } else if (node is Extension) {
-          _classes![node.name] = new _MemberTable.fromExtension(this, node);
+          _classes![node.name!] = new _MemberTable.fromExtension(this, node);
         }
       }
     }
@@ -222,14 +221,14 @@
 
   String getDisambiguatedName(Member member) {
     if (member is Procedure) {
-      if (member.isGetter) return LibraryIndex.getterPrefix + member.name.text;
-      if (member.isSetter) return LibraryIndex.setterPrefix + member.name.text;
+      if (member.isGetter) return LibraryIndex.getterPrefix + member.name!.text;
+      if (member.isSetter) return LibraryIndex.setterPrefix + member.name!.text;
     }
-    return member.name.text;
+    return member.name!.text;
   }
 
   void _addMember(Member member) {
-    if (member.name.isPrivate && member.name.library != library) {
+    if (member.name!.isPrivate && member.name!.library != library) {
       // Members whose name is private to other libraries cannot currently
       // be found with the LibraryIndex class.
       return;
@@ -252,10 +251,10 @@
   }
 
   void _addExtensionMember(ExtensionMemberDescriptor extensionMember) {
-    final NamedNode replacement = extensionMember.member.node;
+    final NamedNode? replacement = extensionMember.member.node;
     if (replacement is! Member) return;
     Member member = replacement;
-    if (member.name.isPrivate && member.name.library != library) {
+    if (member.name!.isPrivate && member.name!.library != library) {
       // Members whose name is private to other libraries cannot currently
       // be found with the LibraryIndex class.
       return;
diff --git a/pkg/kernel/lib/src/assumptions.dart b/pkg/kernel/lib/src/assumptions.dart
index 00b07a9..1d96904 100644
--- a/pkg/kernel/lib/src/assumptions.dart
+++ b/pkg/kernel/lib/src/assumptions.dart
@@ -2,7 +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.
 
-// ignore: import_of_legacy_library_into_null_safe
 import '../ast.dart';
 
 /// Pairs of [TypeParameter]s that are currently assumed to be
diff --git a/pkg/kernel/lib/src/const_canonical_type.dart b/pkg/kernel/lib/src/const_canonical_type.dart
index 186c980..8e0567e 100644
--- a/pkg/kernel/lib/src/const_canonical_type.dart
+++ b/pkg/kernel/lib/src/const_canonical_type.dart
@@ -6,7 +6,7 @@
 
 import 'package:kernel/src/bounds_checks.dart';
 
-import '../ast.dart' hide MapEntry;
+import '../ast.dart';
 import '../core_types.dart';
 import '../type_algebra.dart';
 
diff --git a/pkg/kernel/lib/src/hierarchy_based_type_environment.dart b/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
index 4a02f4e..58186dd 100644
--- a/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
+++ b/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
@@ -4,7 +4,6 @@
 
 library kernel.hierarchy_based_type_environment;
 
-// ignore: import_of_legacy_library_into_null_safe
 import '../ast.dart' show Class, DartType, InterfaceType, Library, Member, Name;
 
 import '../class_hierarchy.dart' show ClassHierarchyBase;
diff --git a/pkg/kernel/lib/src/legacy_erasure.dart b/pkg/kernel/lib/src/legacy_erasure.dart
index fee2dc4..316a701 100644
--- a/pkg/kernel/lib/src/legacy_erasure.dart
+++ b/pkg/kernel/lib/src/legacy_erasure.dart
@@ -2,9 +2,7 @@
 // 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.
 
-// ignore: import_of_legacy_library_into_null_safe
-import '../ast.dart' hide MapEntry;
-
+import '../ast.dart';
 import 'replacement_visitor.dart';
 
 /// Returns legacy erasure of [type], that is, the type in which all nnbd
diff --git a/pkg/kernel/lib/src/merge_visitor.dart b/pkg/kernel/lib/src/merge_visitor.dart
index f089d75..392c59a 100644
--- a/pkg/kernel/lib/src/merge_visitor.dart
+++ b/pkg/kernel/lib/src/merge_visitor.dart
@@ -2,8 +2,7 @@
 // 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.
 
-// ignore: import_of_legacy_library_into_null_safe
-import '../ast.dart' hide MapEntry;
+import '../ast.dart';
 import '../type_algebra.dart';
 
 /// Helper visitor that merges two types, and return the merged type or `null`
@@ -73,13 +72,13 @@
 
       for (int i = 0; i < newTypeParameters.length; i++) {
         DartType? newBound =
-            mergeTypes(a.typeParameters[i].bound, b.typeParameters[i].bound);
+            mergeTypes(a.typeParameters[i].bound!, b.typeParameters[i].bound!);
         if (newBound == null) {
           return null;
         }
         newTypeParameters[i].bound = newBound;
         DartType? newDefaultType = mergeTypes(
-            a.typeParameters[i].defaultType, b.typeParameters[i].defaultType);
+            a.typeParameters[i].defaultType!, b.typeParameters[i].defaultType!);
         if (newDefaultType == null) {
           return null;
         }
@@ -90,7 +89,7 @@
     DartType? newReturnType = mergeTypes(a.returnType, b.returnType);
     if (newReturnType == null) return null;
     List<DartType> newPositionalParameters =
-        new List<DartType>.filled(a.positionalParameters.length, dartTypeDummy);
+        new List<DartType>.filled(a.positionalParameters.length, dummyDartType);
     for (int i = 0; i < a.positionalParameters.length; i++) {
       DartType? newType =
           mergeTypes(a.positionalParameters[i], b.positionalParameters[i]);
@@ -100,7 +99,7 @@
       newPositionalParameters[i] = newType;
     }
     List<NamedType> newNamedParameters =
-        new List<NamedType>.filled(a.namedParameters.length, namedTypeDummy);
+        new List<NamedType>.filled(a.namedParameters.length, dummyNamedType);
     for (int i = 0; i < a.namedParameters.length; i++) {
       DartType? newType =
           mergeTypes(a.namedParameters[i].type, b.namedParameters[i].type);
@@ -116,7 +115,8 @@
     }
     TypedefType? newTypedefType;
     if (a.typedefType != null && b.typedefType != null) {
-      newTypedefType = mergeTypes(a.typedefType, b.typedefType) as TypedefType?;
+      newTypedefType =
+          mergeTypes(a.typedefType!, b.typedefType!) as TypedefType?;
       // If the typedef couldn't be merged we just omit it from the resulting
       // function type since the typedef type is only informational.
     }
@@ -157,7 +157,7 @@
       return new InterfaceType(a.classNode, nullability);
     }
     List<DartType> newTypeArguments =
-        new List<DartType>.filled(a.typeArguments.length, dartTypeDummy);
+        new List<DartType>.filled(a.typeArguments.length, dummyDartType);
     for (int i = 0; i < a.typeArguments.length; i++) {
       DartType? newType = a.typeArguments[i].accept1(this, b.typeArguments[i]);
       if (newType == null) {
@@ -259,7 +259,8 @@
     assert(a.parameter == b.parameter);
     assert(a.promotedBound != null);
     assert(b.promotedBound != null);
-    DartType? newPromotedBound = a.promotedBound.accept1(this, b.promotedBound);
+    DartType? newPromotedBound =
+        a.promotedBound!.accept1(this, b.promotedBound);
     if (newPromotedBound == null) {
       return null;
     }
@@ -287,7 +288,7 @@
       return new TypedefType(a.typedefNode, nullability);
     }
     List<DartType> newTypeArguments =
-        new List<DartType>.filled(a.typeArguments.length, dartTypeDummy);
+        new List<DartType>.filled(a.typeArguments.length, dummyDartType);
     for (int i = 0; i < a.typeArguments.length; i++) {
       DartType? newType = a.typeArguments[i].accept1(this, b.typeArguments[i]);
       if (newType == null) return null;
diff --git a/pkg/kernel/lib/src/nnbd_top_merge.dart b/pkg/kernel/lib/src/nnbd_top_merge.dart
index 7a81f62..632ccc3 100644
--- a/pkg/kernel/lib/src/nnbd_top_merge.dart
+++ b/pkg/kernel/lib/src/nnbd_top_merge.dart
@@ -2,8 +2,7 @@
 // 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.
 
-// ignore: import_of_legacy_library_into_null_safe
-import '../ast.dart' hide MapEntry;
+import '../ast.dart';
 import '../core_types.dart';
 
 import 'merge_visitor.dart';
@@ -17,7 +16,7 @@
     return a;
   }
   List<DartType> newTypeArguments =
-      new List<DartType>.filled(a.typeArguments.length, dartTypeDummy);
+      new List<DartType>.filled(a.typeArguments.length, dummyDartType);
   for (int i = 0; i < a.typeArguments.length; i++) {
     DartType? newTypeArgument =
         nnbdTopMerge(coreTypes, a.typeArguments[i], b.typeArguments[i]);
diff --git a/pkg/kernel/lib/src/non_null.dart b/pkg/kernel/lib/src/non_null.dart
index c3df22a..2223d74 100644
--- a/pkg/kernel/lib/src/non_null.dart
+++ b/pkg/kernel/lib/src/non_null.dart
@@ -2,7 +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.md file.
 
-// ignore: import_of_legacy_library_into_null_safe
 import '../ast.dart';
 
 /// Returns the type defines as `NonNull(type)` in the nnbd specification.
@@ -78,12 +77,12 @@
       return null;
     }
     if (node.promotedBound != null) {
-      if (node.promotedBound.nullability == Nullability.nonNullable) {
+      if (node.promotedBound!.nullability == Nullability.nonNullable) {
         // The promoted bound is already non-nullable so we set the declared
         // nullability to non-nullable.
         return node.withDeclaredNullability(Nullability.nonNullable);
       }
-      DartType? promotedBound = node.promotedBound.accept(this);
+      DartType? promotedBound = node.promotedBound!.accept(this);
       if (promotedBound == null) {
         // The promoted bound could not be made non-nullable so we set the
         // declared nullability to undetermined.
@@ -91,7 +90,7 @@
           return null;
         }
         return new TypeParameterType.intersection(
-            node.parameter, Nullability.undetermined, node.promotedBound);
+            node.parameter, Nullability.undetermined, node.promotedBound!);
       } else if (promotedBound.nullability == Nullability.nonNullable) {
         // The bound could be made non-nullable so we use it as the promoted
         // bound.
diff --git a/pkg/kernel/lib/src/norm.dart b/pkg/kernel/lib/src/norm.dart
index f828120..78ab826 100644
--- a/pkg/kernel/lib/src/norm.dart
+++ b/pkg/kernel/lib/src/norm.dart
@@ -2,8 +2,7 @@
 // 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.
 
-// ignore: import_of_legacy_library_into_null_safe
-import '../ast.dart' hide MapEntry;
+import '../ast.dart';
 import '../core_types.dart';
 import '../type_algebra.dart';
 
@@ -94,7 +93,7 @@
   @override
   DartType? visitTypeParameterType(TypeParameterType node, int variance) {
     if (node.promotedBound == null) {
-      DartType bound = node.parameter.bound;
+      DartType bound = node.parameter.bound!;
       if (normalizesToNever(bound)) {
         DartType result = NeverType.fromNullability(node.nullability);
         return result.accept1(this, variance) ?? result;
@@ -103,7 +102,7 @@
       // If the bound isn't Never, the type is already normalized.
       return null;
     } else {
-      DartType bound = node.promotedBound;
+      DartType bound = node.promotedBound!;
       bound = bound.accept1(this, variance) ?? bound;
       if (bound is NeverType && bound.nullability == Nullability.nonNullable) {
         return bound;
@@ -119,7 +118,7 @@
         assert(!coreTypes.isTop(bound));
         return new TypeParameterType(node.parameter, node.declaredNullability);
       } else if (bound == coreTypes.objectNonNullableRawType &&
-          norm(coreTypes, node.parameter.bound) ==
+          norm(coreTypes, node.parameter.bound!) ==
               coreTypes.objectNonNullableRawType) {
         return new TypeParameterType(node.parameter, node.declaredNullability);
       } else if (identical(bound, node.promotedBound)) {
@@ -144,9 +143,9 @@
       return true;
     } else if (type is TypeParameterType) {
       if (type.promotedBound == null) {
-        return normalizesToNever(type.parameter.bound);
+        return normalizesToNever(type.parameter.bound!);
       } else {
-        return normalizesToNever(type.promotedBound);
+        return normalizesToNever(type.promotedBound!);
       }
     }
     return false;
diff --git a/pkg/kernel/lib/src/printer.dart b/pkg/kernel/lib/src/printer.dart
index d14c8cd..5874ca7 100644
--- a/pkg/kernel/lib/src/printer.dart
+++ b/pkg/kernel/lib/src/printer.dart
@@ -2,7 +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.
 
-// ignore: import_of_legacy_library_into_null_safe
 import '../ast.dart';
 import 'text_util.dart';
 
@@ -157,8 +156,9 @@
   }
 
   String getVariableName(VariableDeclaration node) {
-    if (node.name != null) {
-      return node.name;
+    String? name = node.name;
+    if (name != null) {
+      return name;
     }
     return _variableNames[node] ??= '#${_variableNames.length}';
   }
@@ -259,22 +259,22 @@
       for (TypeParameter typeParameter in typeParameters) {
         _sb.write(comma);
         _sb.write(typeParameter.name);
-        DartType bound = typeParameter.bound;
+        DartType bound = typeParameter.bound!;
 
         bool isTopObject(DartType type) {
           if (type is InterfaceType &&
               type.className.node != null &&
               type.classNode.name == 'Object') {
-            Uri? uri = type.classNode.enclosingLibrary?.importUri;
-            return uri?.scheme == 'dart' &&
-                uri?.path == 'core' &&
+            Uri uri = type.classNode.enclosingLibrary.importUri;
+            return uri.scheme == 'dart' &&
+                uri.path == 'core' &&
                 (type.nullability == Nullability.legacy ||
                     type.nullability == Nullability.nullable);
           }
           return false;
         }
 
-        if (!isTopObject(bound) || isTopObject(typeParameter.defaultType)) {
+        if (!isTopObject(bound) || isTopObject(typeParameter.defaultType!)) {
           // Include explicit bounds only.
           _sb.write(' extends ');
           writeType(bound);
@@ -385,7 +385,7 @@
     _sb.write(getVariableName(node));
     if (includeInitializer && node.initializer != null && !node.isRequired) {
       _sb.write(' = ');
-      writeExpression(node.initializer);
+      writeExpression(node.initializer!);
     }
   }
 
@@ -401,7 +401,7 @@
         }
         _sb.write(node.typeParameters[index].name);
         _sb.write(' extends ');
-        writeType(node.typeParameters[index].bound);
+        writeType(node.typeParameters[index].bound!);
       }
       _sb.write('>');
     }
@@ -437,7 +437,7 @@
     if (body != null) {
       if (body is ReturnStatement) {
         _sb.write(' => ');
-        writeExpression(body.expression);
+        writeExpression(body.expression!);
       } else {
         _sb.write(' ');
         writeStatement(body);
diff --git a/pkg/kernel/lib/src/replacement_visitor.dart b/pkg/kernel/lib/src/replacement_visitor.dart
index 45e823e..8fbce4a 100644
--- a/pkg/kernel/lib/src/replacement_visitor.dart
+++ b/pkg/kernel/lib/src/replacement_visitor.dart
@@ -2,8 +2,7 @@
 // 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.
 
-// ignore: import_of_legacy_library_into_null_safe
-import '../ast.dart' hide MapEntry;
+import '../ast.dart';
 import '../type_algebra.dart';
 
 /// Helper visitor that clones a type if a nested type is replaced, and
@@ -49,7 +48,7 @@
           Substitution.fromPairs(node.typeParameters, typeParameterTypes);
       for (int i = 0; i < newTypeParameters.length; i++) {
         newTypeParameters[i].bound =
-            substitution.substituteType(newTypeParameters[i].bound);
+            substitution.substituteType(newTypeParameters[i].bound!);
       }
     }
 
@@ -211,7 +210,7 @@
   DartType? visitTypeParameterType(TypeParameterType node, int variance) {
     Nullability? newNullability = visitNullability(node);
     if (node.promotedBound != null) {
-      DartType newPromotedBound = node.promotedBound.accept1(this, variance);
+      DartType? newPromotedBound = node.promotedBound!.accept1(this, variance);
       return createPromotedTypeParameterType(
           node, newNullability, newPromotedBound);
     }
diff --git a/pkg/kernel/lib/src/standard_bounds.dart b/pkg/kernel/lib/src/standard_bounds.dart
index efab942..dba4d98 100644
--- a/pkg/kernel/lib/src/standard_bounds.dart
+++ b/pkg/kernel/lib/src/standard_bounds.dart
@@ -4,8 +4,7 @@
 
 import 'dart:math' as math;
 
-// ignore: import_of_legacy_library_into_null_safe
-import '../ast.dart' hide MapEntry;
+import '../ast.dart';
 import '../class_hierarchy.dart';
 import '../core_types.dart';
 import '../type_algebra.dart';
@@ -216,7 +215,7 @@
         s.promotedBound != null &&
         t is TypeParameterType &&
         t.promotedBound != null) {
-      return morebottom(s.promotedBound, t.promotedBound);
+      return morebottom(s.promotedBound!, t.promotedBound!);
     }
 
     // MOREBOTTOM(X&S, T) = true.
@@ -233,7 +232,7 @@
     if (s is TypeParameterType && t is TypeParameterType) {
       assert(s.promotedBound == null);
       assert(t.promotedBound == null);
-      return morebottom(s.parameter.bound, t.parameter.bound);
+      return morebottom(s.parameter.bound!, t.parameter.bound!);
     }
 
     throw new UnsupportedError("morebottom($s, $t)");
@@ -950,8 +949,8 @@
           // TODO(dmitryas): Figure out if a procedure for syntactic equality
           // should be used instead.
           if (!areMutualSubtypes(
-              f.typeParameters[i].bound,
-              substitution.substituteType(g.typeParameters[i].bound),
+              f.typeParameters[i].bound!,
+              substitution.substituteType(g.typeParameters[i].bound!),
               SubtypeCheckMode.withNullabilities)) {
             boundsMatch = false;
           }
@@ -967,7 +966,7 @@
     List<TypeParameter> typeParameters = f.typeParameters;
 
     List<DartType> positionalParameters =
-        new List<DartType>.filled(maxPos, dartTypeDummy);
+        new List<DartType>.filled(maxPos, dummyDartType);
     for (int i = 0; i < minPos; ++i) {
       positionalParameters[i] = _getNullabilityAwareStandardUpperBound(
           f.positionalParameters[i],
@@ -1149,8 +1148,8 @@
           // TODO(dmitryas): Figure out if a procedure for syntactic
           // equality should be used instead.
           if (!areMutualSubtypes(
-              f.typeParameters[i].bound,
-              substitution.substituteType(g.typeParameters[i].bound),
+              f.typeParameters[i].bound!,
+              substitution.substituteType(g.typeParameters[i].bound!),
               SubtypeCheckMode.withNullabilities)) {
             boundsMatch = false;
           }
@@ -1164,7 +1163,7 @@
     List<TypeParameter> typeParameters = f.typeParameters;
 
     List<DartType> positionalParameters =
-        new List<DartType>.filled(minPos, dartTypeDummy);
+        new List<DartType>.filled(minPos, dummyDartType);
     for (int i = 0; i < minPos; ++i) {
       positionalParameters[i] = _getNullabilityAwareStandardLowerBound(
           f.positionalParameters[i],
@@ -1233,12 +1232,12 @@
               topFunctionType: coreTypes.functionNonNullableRawType,
               unhandledTypeHandler: (type, recursor) => false);
       return _getNullabilityAwareStandardUpperBound(
-              eliminator.eliminateToGreatest(type1.parameter.bound),
+              eliminator.eliminateToGreatest(type1.parameter.bound!),
               type2,
               clientLibrary)
           .withDeclaredNullability(uniteNullabilities(
               type1.declaredNullability,
-              uniteNullabilities(type1.parameter.bound.declaredNullability,
+              uniteNullabilities(type1.parameter.bound!.declaredNullability,
                   type2.declaredNullability)));
     } else {
       // UP(X1 & B1, T2) =
@@ -1265,11 +1264,11 @@
               topFunctionType: coreTypes.functionNonNullableRawType,
               unhandledTypeHandler: (type, recursor) => false);
       return _getNullabilityAwareStandardUpperBound(
-              eliminator.eliminateToGreatest(type1.promotedBound),
+              eliminator.eliminateToGreatest(type1.promotedBound!),
               type2,
               clientLibrary)
           .withDeclaredNullability(uniteNullabilities(
-              type1.promotedBound.declaredNullability,
+              type1.promotedBound!.declaredNullability,
               type2.declaredNullability));
     }
   }
@@ -1419,7 +1418,7 @@
     int totalPositional =
         math.max(f.positionalParameters.length, g.positionalParameters.length);
     List<DartType> positionalParameters =
-        new List<DartType>.filled(totalPositional, dartTypeDummy);
+        new List<DartType>.filled(totalPositional, dummyDartType);
     for (int i = 0; i < totalPositional; i++) {
       if (i < f.positionalParameters.length) {
         DartType fType = f.positionalParameters[i];
@@ -1523,7 +1522,7 @@
     int totalPositional =
         math.min(f.positionalParameters.length, g.positionalParameters.length);
     List<DartType> positionalParameters =
-        new List<DartType>.filled(totalPositional, dartTypeDummy);
+        new List<DartType>.filled(totalPositional, dummyDartType);
     for (int i = 0; i < totalPositional; i++) {
       positionalParameters[i] = getStandardLowerBound(
           f.positionalParameters[i], g.positionalParameters[i], clientLibrary);
@@ -1602,7 +1601,7 @@
 
       assert(tArgs1.length == tArgs2.length);
       assert(tArgs1.length == tParams.length);
-      List<DartType> tArgs = new List.filled(tArgs1.length, dartTypeDummy);
+      List<DartType> tArgs = new List.filled(tArgs1.length, dummyDartType);
       for (int i = 0; i < tArgs1.length; i++) {
         if (tParams[i].variance == Variance.contravariant) {
           tArgs[i] = getStandardLowerBound(tArgs1[i], tArgs2[i], clientLibrary);
@@ -1675,14 +1674,14 @@
       // we need to replicate that behavior?
       return getStandardUpperBound(
           Substitution.fromMap({type1.parameter: coreTypes.objectLegacyRawType})
-              .substituteType(type1.parameter.bound),
+              .substituteType(type1.parameter.bound!),
           type2,
           clientLibrary);
     } else if (type2 is TypeParameterType) {
       return getStandardUpperBound(
           type1,
           Substitution.fromMap({type2.parameter: coreTypes.objectLegacyRawType})
-              .substituteType(type2.parameter.bound),
+              .substituteType(type2.parameter.bound!),
           clientLibrary);
     } else {
       // We should only be called when at least one of the types is a
diff --git a/pkg/kernel/lib/src/text_util.dart b/pkg/kernel/lib/src/text_util.dart
index 0e9e0cc..873fafb 100644
--- a/pkg/kernel/lib/src/text_util.dart
+++ b/pkg/kernel/lib/src/text_util.dart
@@ -2,7 +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.
 
-// ignore: import_of_legacy_library_into_null_safe
 import '../ast.dart';
 
 String nullabilityToString(Nullability nullability) {
@@ -47,17 +46,17 @@
     {bool includeLibraryName: false}) {
   if (canonicalName.isRoot) {
     return '<root>';
-  } else if (canonicalName.parent.isRoot) {
+  } else if (canonicalName.parent!.isRoot) {
     return canonicalName.name;
-  } else if (canonicalName.parent.parent.isRoot) {
+  } else if (canonicalName.parent!.parent!.isRoot) {
     if (!includeLibraryName) {
       return canonicalName.name;
     }
-    String parentName = qualifiedCanonicalNameToString(canonicalName.parent,
+    String parentName = qualifiedCanonicalNameToString(canonicalName.parent!,
         includeLibraryName: includeLibraryName);
     return '$parentName::${canonicalName.name}';
   } else {
-    String parentName = qualifiedCanonicalNameToString(canonicalName.parent,
+    String parentName = qualifiedCanonicalNameToString(canonicalName.parent!,
         includeLibraryName: includeLibraryName);
     return '$parentName.${canonicalName.name}';
   }
@@ -165,15 +164,13 @@
 }
 
 String typedefNameToString(Typedef? node) {
-  return node == null
-      ? 'null'
-      : node.name ?? 'null-named typedef ${node.runtimeType} ${node.hashCode}';
+  return node == null ? 'null' : node.name;
 }
 
 String qualifiedMemberNameToString(Member node,
     {bool includeLibraryName: false}) {
   if (node.enclosingClass != null) {
-    return qualifiedClassNameToString(node.enclosingClass,
+    return qualifiedClassNameToString(node.enclosingClass!,
             includeLibraryName: includeLibraryName) +
         '.' +
         memberNameToString(node);
@@ -215,7 +212,7 @@
 
 String qualifiedTypeParameterNameToString(TypeParameter node,
     {bool includeLibraryName: false}) {
-  TreeNode parent = node.parent;
+  TreeNode? parent = node.parent;
   if (parent is Class) {
     return qualifiedClassNameToString(parent,
             includeLibraryName: includeLibraryName) +
diff --git a/pkg/kernel/lib/src/types.dart b/pkg/kernel/lib/src/types.dart
index b54c79d..119100c 100644
--- a/pkg/kernel/lib/src/types.dart
+++ b/pkg/kernel/lib/src/types.dart
@@ -2,7 +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.
 
-// ignore: import_of_legacy_library_into_null_safe
 import '../ast.dart'
     show
         BottomType,
@@ -381,7 +380,7 @@
   IsSubtypeOf isTypeParameterRelated(
       TypeParameterType s, InterfaceType t, Types types) {
     return types
-        .performNullabilityAwareSubtypeCheck(s.parameter.bound, t)
+        .performNullabilityAwareSubtypeCheck(s.parameter.bound!, t)
         .and(new IsSubtypeOf.basedSolelyOnNullabilities(s, t));
   }
 
@@ -402,7 +401,7 @@
   IsSubtypeOf isIntersectionRelated(
       TypeParameterType intersection, InterfaceType t, Types types) {
     return types.performNullabilityAwareSubtypeCheck(
-        intersection.promotedBound, t); // Rule 12.
+        intersection.promotedBound!, t); // Rule 12.
   }
 
   @override
@@ -454,7 +453,7 @@
         TypeParameter sTypeVariable = sTypeVariables[i];
         TypeParameter tTypeVariable = tTypeVariables[i];
         result = result.and(types.performNullabilityAwareMutualSubtypesCheck(
-            sTypeVariable.bound, tTypeVariable.bound));
+            sTypeVariable.bound!, tTypeVariable.bound!));
         typeVariableSubstitution.add(new TypeParameterType.forAlphaRenaming(
             sTypeVariable, tTypeVariable));
       }
@@ -468,8 +467,8 @@
           TypeParameter sTypeVariable = sTypeVariables[i];
           TypeParameter tTypeVariable = tTypeVariables[i];
           result = result.and(types.performNullabilityAwareMutualSubtypesCheck(
-              substitution.substituteType(sTypeVariable.bound),
-              tTypeVariable.bound));
+              substitution.substituteType(sTypeVariable.bound!),
+              tTypeVariable.bound!));
           if (!result.isSubtypeWhenIgnoringNullabilities()) {
             return const IsSubtypeOf.never();
           }
@@ -582,7 +581,7 @@
       TypeParameterType intersection, FunctionType t, Types types) {
     // Rule 12.
     return types.performNullabilityAwareSubtypeCheck(
-        intersection.promotedBound, t);
+        intersection.promotedBound!, t);
   }
 
   @override
@@ -590,7 +589,7 @@
       TypeParameterType s, FunctionType t, Types types) {
     // Rule 13.
     return types
-        .performNullabilityAwareSubtypeCheck(s.parameter.bound, t)
+        .performNullabilityAwareSubtypeCheck(s.parameter.bound!, t)
         .and(new IsSubtypeOf.basedSolelyOnNullabilities(s, t));
   }
 
@@ -645,7 +644,7 @@
 
     // Rule 12.
     return types.performNullabilityAwareSubtypeCheck(
-        intersection.promotedBound
+        intersection.promotedBound!
             .withDeclaredNullability(intersection.nullability),
         t);
   }
@@ -826,9 +825,9 @@
             s, t.typeArgument.withDeclaredNullability(t.nullability))
         // Rule 13.
         .orSubtypeCheckFor(
-            s.parameter.bound.withDeclaredNullability(
+            s.parameter.bound!.withDeclaredNullability(
                 combineNullabilitiesForSubstitution(
-                    s.parameter.bound.nullability, s.nullability)),
+                    s.parameter.bound!.nullability, s.nullability)),
             t,
             types)
         // Rule 10.
@@ -850,7 +849,7 @@
   IsSubtypeOf isIntersectionRelated(
       TypeParameterType intersection, FutureOrType t, Types types) {
     return isTypeParameterRelated(intersection, t, types) // Rule 8.
-        .orSubtypeCheckFor(intersection.promotedBound, t, types); // Rule 12.
+        .orSubtypeCheckFor(intersection.promotedBound!, t, types); // Rule 12.
   }
 
   @override
@@ -868,7 +867,7 @@
     // Rule 9.
     return const IsTypeParameterSubtypeOf()
         .isIntersectionRelated(sIntersection, tIntersection, types)
-        .andSubtypeCheckFor(sIntersection, tIntersection.promotedBound, types);
+        .andSubtypeCheckFor(sIntersection, tIntersection.promotedBound!, types);
   }
 
   @override
@@ -877,7 +876,7 @@
     // Rule 9.
     return const IsTypeParameterSubtypeOf()
         .isTypeParameterRelated(s, intersection, types)
-        .andSubtypeCheckFor(s, intersection.promotedBound, types);
+        .andSubtypeCheckFor(s, intersection.promotedBound!, types);
   }
 
   @override
@@ -936,7 +935,7 @@
   IsSubtypeOf isIntersectionRelated(
       TypeParameterType intersection, NullType t, Types types) {
     return types.performNullabilityAwareMutualSubtypesCheck(
-        intersection.promotedBound, t);
+        intersection.promotedBound!, t);
   }
 
   IsSubtypeOf isFunctionRelated(FunctionType s, NullType t, Types types) {
@@ -978,7 +977,7 @@
   IsSubtypeOf isIntersectionRelated(
       TypeParameterType intersection, NeverType t, Types types) {
     return types.performNullabilityAwareSubtypeCheck(
-        intersection.promotedBound, t);
+        intersection.promotedBound!, t);
   }
 
   IsSubtypeOf isFunctionRelated(FunctionType s, NeverType t, Types types) {
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 26699f0..871f92b 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.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.
 
-// @dart = 2.9
-
 library kernel.ast_to_text;
 
 import 'dart:core' hide MapEntry;
@@ -26,11 +24,13 @@
 
 class NormalNamer<T> extends Namer<T> {
   final String prefix;
+
   NormalNamer(this.prefix);
 }
 
 class ConstantNamer extends RecursiveResultVisitor<Null> with Namer<Constant> {
   final String prefix;
+
   ConstantNamer(this.prefix);
 
   String getName(Constant constant) {
@@ -78,7 +78,7 @@
   final Map<U, String> namesU = <U, String>{};
   final Set<String> usedNames = new Set<String>();
 
-  String disambiguate(T key1, U key2, String proposeName()) {
+  String disambiguate(T? key1, U? key2, String proposeName()) {
     String getNewName() {
       String proposedName = proposeName();
       if (usedNames.add(proposedName)) return proposedName;
@@ -90,12 +90,12 @@
     }
 
     if (key1 != null) {
-      String result = namesT[key1];
+      String? result = namesT[key1];
       if (result != null) return result;
       return namesT[key1] = getNewName();
     }
     if (key2 != null) {
-      String result = namesU[key2];
+      String? result = namesU[key2];
       if (result != null) return result;
       return namesU[key2] = getNewName();
     }
@@ -105,13 +105,13 @@
 
 NameSystem globalDebuggingNames = new NameSystem();
 
-String debugLibraryName(Library node) {
+String debugLibraryName(Library? node) {
   return node == null
       ? 'null'
       : node.name ?? globalDebuggingNames.nameLibrary(node);
 }
 
-String debugClassName(Class node) {
+String debugClassName(Class? node) {
   return node == null
       ? 'null'
       : node.name ?? globalDebuggingNames.nameClass(node);
@@ -127,7 +127,7 @@
 
 String debugQualifiedMemberName(Member node) {
   if (node.enclosingClass != null) {
-    return debugQualifiedClassName(node.enclosingClass) +
+    return debugQualifiedClassName(node.enclosingClass!) +
         '::' +
         debugMemberName(node);
   } else {
@@ -142,13 +142,14 @@
 }
 
 String debugQualifiedTypeParameterName(TypeParameter node) {
-  if (node.parent is Class) {
-    return debugQualifiedClassName(node.parent) +
+  TreeNode? parent = node.parent;
+  if (parent is Class) {
+    return debugQualifiedClassName(parent) +
         '::' +
         debugTypeParameterName(node);
   }
-  if (node.parent is Member) {
-    return debugQualifiedMemberName(node.parent) +
+  if (parent is Member) {
+    return debugQualifiedMemberName(parent) +
         '::' +
         debugTypeParameterName(node);
   }
@@ -212,11 +213,17 @@
 
   final RegExp pathSeparator = new RegExp('[\\/]');
 
-  String nameLibraryPrefix(Library node, {String proposedName}) {
+  String nameLibraryPrefix(Library node, {String? proposedName}) {
     return prefixes.disambiguate(node.reference, node.reference.canonicalName,
         () {
-      if (proposedName != null) return proposedName;
-      if (node.name != null) return abbreviateName(node.name);
+      if (proposedName != null) {
+        return proposedName;
+      }
+      String? name = node.name;
+      if (name != null) {
+        return abbreviateName(name);
+      }
+      // ignore: unnecessary_null_comparison
       if (node.importUri != null) {
         String path = node.importUri.hasEmptyPath
             ? '${node.importUri}'
@@ -230,13 +237,13 @@
     });
   }
 
-  nameCanonicalNameAsLibraryPrefix(Reference node, CanonicalName name,
-      {String proposedName}) {
+  nameCanonicalNameAsLibraryPrefix(Reference? node, CanonicalName? name,
+      {String? proposedName}) {
     return prefixes.disambiguate(node, name, () {
       if (proposedName != null) return proposedName;
-      CanonicalName canonicalName = name ?? node.canonicalName;
+      CanonicalName? canonicalName = name ?? node?.canonicalName;
       if (canonicalName?.name != null) {
-        String path = canonicalName.name;
+        String path = canonicalName!.name;
         int slash = path.lastIndexOf(pathSeparator);
         if (slash >= 0) {
           path = path.substring(slash + 1);
@@ -274,9 +281,9 @@
 class Printer extends Visitor<void> with VisitorVoidMixin {
   final NameSystem syntheticNames;
   final StringSink sink;
-  final Annotator annotator;
-  final Map<String, MetadataRepository<Object>> metadata;
-  ImportTable importTable;
+  final Annotator? annotator;
+  final Map<String, MetadataRepository<dynamic>>? metadata;
+  ImportTable? importTable;
   int indentation = 0;
   int column = 0;
   bool showOffsets;
@@ -288,7 +295,7 @@
   int state = SPACE;
 
   Printer(this.sink,
-      {NameSystem syntheticNames,
+      {NameSystem? syntheticNames,
       this.showOffsets: false,
       this.showMetadata: false,
       this.importTable,
@@ -297,7 +304,7 @@
       : this.syntheticNames = syntheticNames ?? new NameSystem();
 
   Printer createInner(ImportTable importTable,
-      Map<String, MetadataRepository<Object>> metadata) {
+      Map<String, MetadataRepository<dynamic>>? metadata) {
     return new Printer(sink,
         importTable: importTable,
         metadata: metadata,
@@ -319,8 +326,9 @@
   }
 
   String getLibraryReference(Library node) {
+    // ignore: unnecessary_null_comparison
     if (node == null) return '<No Library>';
-    if (importTable != null && importTable.getImportIndex(node) != -1) {
+    if (importTable != null && importTable?.getImportIndex(node) != -1) {
       return syntheticNames.nameLibraryPrefix(node);
     }
     return getLibraryName(node);
@@ -335,6 +343,7 @@
   }
 
   String getClassReference(Class node) {
+    // ignore: unnecessary_null_comparison
     if (node == null) return '<No Class>';
     String name = getClassName(node);
     String library = getLibraryReference(node.enclosingLibrary);
@@ -342,6 +351,7 @@
   }
 
   String getTypedefReference(Typedef node) {
+    // ignore: unnecessary_null_comparison
     if (node == null) return '<No Typedef>';
     String library = getLibraryReference(node.enclosingLibrary);
     return '$library::${node.name}';
@@ -352,15 +362,17 @@
 
   Name getMemberName(Member node) {
     if (node.name?.text == '') return emptyName;
-    if (node.name != null) return node.name;
+    if (node.name != null) return node.name!;
     return new Name(syntheticNames.nameMember(node));
   }
 
   String getMemberReference(Member node) {
+    // ignore: unnecessary_null_comparison
     if (node == null) return '<No Member>';
     String name = getMemberName(node).text;
-    if (node.parent is Class) {
-      String className = getClassReference(node.parent);
+    Class? enclosingClass = node.enclosingClass;
+    if (enclosingClass != null) {
+      String className = getClassReference(enclosingClass);
       return '$className::$name';
     } else {
       String library = getLibraryReference(node.enclosingLibrary);
@@ -373,6 +385,7 @@
   }
 
   String getVariableReference(VariableDeclaration node) {
+    // ignore: unnecessary_null_comparison
     if (node == null) return '<No VariableDeclaration>';
     return getVariableName(node);
   }
@@ -382,13 +395,15 @@
   }
 
   String getTypeParameterReference(TypeParameter node) {
+    // ignore: unnecessary_null_comparison
     if (node == null) return '<No TypeParameter>';
     String name = getTypeParameterName(node);
-    if (node.parent is FunctionNode && node.parent.parent is Member) {
-      String member = getMemberReference(node.parent.parent);
+    TreeNode? parent = node.parent;
+    if (parent is FunctionNode && parent.parent is Member) {
+      String member = getMemberReference(parent.parent as Member);
       return '$member::$name';
-    } else if (node.parent is Class) {
-      String className = getClassReference(node.parent);
+    } else if (parent is Class) {
+      String className = getClassReference(parent);
       return '$className::$name';
     } else {
       return name; // Bound inside a function type.
@@ -399,8 +414,8 @@
     writeProblemsAsJson("Problems in component", component.problemsAsJson);
   }
 
-  void writeProblemsAsJson(String header, List<String> problemsAsJson) {
-    if (problemsAsJson?.isEmpty == false) {
+  void writeProblemsAsJson(String header, List<String>? problemsAsJson) {
+    if (problemsAsJson != null && problemsAsJson.isNotEmpty) {
       endLine("//");
       write("// ");
       write(header);
@@ -408,7 +423,8 @@
       endLine("//");
       for (String s in problemsAsJson) {
         Map<String, Object> decoded = json.decode(s);
-        List<Object> plainTextFormatted = decoded["plainTextFormatted"];
+        List<Object> plainTextFormatted =
+            decoded["plainTextFormatted"] as List<Object>;
         List<String> lines = plainTextFormatted.join("\n").split("\n");
         for (int i = 0; i < lines.length; i++) {
           write("//");
@@ -424,8 +440,9 @@
   void writeLibraryFile(Library library) {
     writeAnnotationList(library.annotations);
     writeWord('library');
-    if (library.name != null) {
-      writeWord(library.name);
+    String? name = library.name;
+    if (name != null) {
+      writeWord(name);
     }
     if (library.isNonNullableByDefault) {
       writeWord("/*isNonNullableByDefault*/");
@@ -453,7 +470,7 @@
   }
 
   void writeStandardLibraryContent(Library library,
-      {Printer outerPrinter, LibraryImportTable importsToPrint}) {
+      {Printer? outerPrinter, LibraryImportTable? importsToPrint}) {
     outerPrinter ??= this;
     outerPrinter.writeProblemsAsJson(
         "Problems in library", library.problemsAsJson);
@@ -479,23 +496,23 @@
     write('additionalExports = (');
     for (int i = 0; i < additionalExports.length; i++) {
       Reference reference = additionalExports[i];
-      NamedNode node = reference.node;
+      NamedNode? node = reference.node;
       if (node is Class) {
         Library nodeLibrary = node.enclosingLibrary;
         String prefix = syntheticNames.nameLibraryPrefix(nodeLibrary);
-        write(prefix + '::' + node.name);
+        write(prefix + '::' + node.name!);
       } else if (node is Extension) {
         Library nodeLibrary = node.enclosingLibrary;
         String prefix = syntheticNames.nameLibraryPrefix(nodeLibrary);
-        write(prefix + '::' + node.name);
+        write(prefix + '::' + node.name!);
       } else if (node is Field) {
         Library nodeLibrary = node.enclosingLibrary;
         String prefix = syntheticNames.nameLibraryPrefix(nodeLibrary);
-        write(prefix + '::' + node.name.text);
+        write(prefix + '::' + node.name!.text);
       } else if (node is Procedure) {
         Library nodeLibrary = node.enclosingLibrary;
         String prefix = syntheticNames.nameLibraryPrefix(nodeLibrary);
-        write(prefix + '::' + node.name.text);
+        write(prefix + '::' + node.name!.text);
       } else if (node is Typedef) {
         Library nodeLibrary = node.enclosingLibrary;
         String prefix = syntheticNames.nameLibraryPrefix(nodeLibrary);
@@ -532,9 +549,11 @@
       }
       writeAnnotationList(library.annotations);
       writeWord('library');
-      if (library.name != null) {
-        writeWord(library.name);
+      String? name = library.name;
+      if (name != null) {
+        writeWord(name);
       }
+      // ignore: unnecessary_null_comparison
       if (library.importUri != null) {
         writeSpaced('from');
         writeWord('"${library.importUri}"');
@@ -567,7 +586,7 @@
     endLine('}');
   }
 
-  int getPrecedence(TreeNode node) {
+  int getPrecedence(Expression node) {
     return Precedence.of(node);
   }
 
@@ -618,7 +637,7 @@
     writeSpace('  ' * indentation);
   }
 
-  void writeNode(Node node) {
+  void writeNode(Node? node) {
     if (node == null) {
       writeSymbol("<Null>");
     } else {
@@ -642,16 +661,10 @@
     }
   }
 
-  void writeOptionalNode(Node node) {
-    if (node != null) {
-      node.accept(this);
-    }
-  }
-
   void writeMetadata(TreeNode node) {
     if (metadata != null) {
-      for (MetadataRepository<Object> md in metadata.values) {
-        final Object nodeMetadata = md.mapping[node];
+      for (MetadataRepository<dynamic> md in metadata!.values) {
+        final dynamic nodeMetadata = md.mapping[node];
         if (nodeMetadata != null) {
           writeWord("[@${md.tag}=${nodeMetadata}]");
         }
@@ -659,7 +672,7 @@
     }
   }
 
-  void writeAnnotatedType(DartType type, String annotation) {
+  void writeAnnotatedType(DartType type, String? annotation) {
     writeType(type);
     if (annotation != null) {
       write('/');
@@ -669,6 +682,7 @@
   }
 
   void writeType(DartType type) {
+    // ignore: unnecessary_null_comparison
     if (type == null) {
       write('<No DartType>');
     } else {
@@ -677,12 +691,14 @@
   }
 
   void writeOptionalType(DartType type) {
+    // ignore: unnecessary_null_comparison
     if (type != null) {
       type.accept(this);
     }
   }
 
   visitSupertype(Supertype type) {
+    // ignore: unnecessary_null_comparison
     if (type == null) {
       write('<No Supertype>');
     } else {
@@ -711,14 +727,14 @@
   }
 
   void writeName(Name name) {
-    if (name?.text == '') {
+    if (name.text == '') {
       writeWord(emptyNameString);
     } else {
-      writeWord(name?.text ?? '<anonymous>'); // TODO: write library name
+      writeWord(name.text); // TODO: write library name
     }
   }
 
-  void endLine([String string]) {
+  void endLine([String? string]) {
     if (string != null) {
       write(string);
     }
@@ -728,7 +744,7 @@
   }
 
   void writeFunction(FunctionNode function,
-      {name, List<Initializer> initializers, bool terminateLine: true}) {
+      {name, List<Initializer>? initializers, bool terminateLine: true}) {
     if (name is String) {
       writeWord(name);
     } else if (name is Name) {
@@ -758,8 +774,9 @@
       writeSpaced(getAsyncMarkerKeyword(function.dartAsyncMarker));
       writeSpaced("*/");
     }
-    if (function.body != null) {
-      writeFunctionBody(function.body, terminateLine: terminateLine);
+    Statement? body = function.body;
+    if (body != null) {
+      writeFunctionBody(body, terminateLine: terminateLine);
     } else if (terminateLine) {
       endLine(';');
     } else {
@@ -806,15 +823,15 @@
       }
     } else if (body is ReturnStatement && !terminateLine) {
       writeSpaced('=>');
-      writeExpression(body.expression);
+      writeExpression(body.expression!);
     } else {
       writeBody(body);
     }
   }
 
   writeFunctionType(FunctionType node,
-      {List<VariableDeclaration> typedefPositional,
-      List<VariableDeclaration> typedefNamed}) {
+      {List<VariableDeclaration>? typedefPositional,
+      List<VariableDeclaration>? typedefNamed}) {
     if (state == WORD) {
       ensureSpace();
     }
@@ -892,7 +909,8 @@
     }
   }
 
-  void writeReturnType(DartType type, String annotation) {
+  void writeReturnType(DartType type, String? annotation) {
+    // ignore: unnecessary_null_comparison
     if (type == null) return;
     writeSpaced('→');
     writeAnnotatedType(type, annotation);
@@ -949,23 +967,24 @@
   }
 
   String getClassReferenceFromReference(Reference reference) {
+    // ignore: unnecessary_null_comparison
     if (reference == null) return '<No Class>';
     if (reference.node != null) return getClassReference(reference.asClass);
     if (reference.canonicalName != null) {
-      return getCanonicalNameString(reference.canonicalName);
+      return getCanonicalNameString(reference.canonicalName!);
     }
     throw "Neither node nor canonical name found";
   }
 
-  void writeMemberReferenceFromReference(Reference reference) {
+  void writeMemberReferenceFromReference(Reference? reference) {
     writeWord(getMemberReferenceFromReference(reference));
   }
 
-  String getMemberReferenceFromReference(Reference reference) {
+  String getMemberReferenceFromReference(Reference? reference) {
     if (reference == null) return '<No Member>';
     if (reference.node != null) return getMemberReference(reference.asMember);
     if (reference.canonicalName != null) {
-      return getCanonicalNameString(reference.canonicalName);
+      return getCanonicalNameString(reference.canonicalName!);
     }
     throw "Neither node nor canonical name found";
   }
@@ -976,28 +995,28 @@
 
     String libraryString(CanonicalName lib) {
       if (lib.reference?.node != null) {
-        return getLibraryReference(lib.reference.asLibrary);
+        return getLibraryReference(lib.reference!.asLibrary);
       }
       return syntheticNames.nameCanonicalNameAsLibraryPrefix(
           lib.reference, lib);
     }
 
     String classString(CanonicalName cls) =>
-        libraryString(cls.parent) + '::' + cls.name;
+        libraryString(cls.parent!) + '::' + cls.name;
 
-    if (name.parent.isRoot) return libraryString(name);
-    if (name.parent.parent.isRoot) return classString(name);
+    if (name.parent!.isRoot) return libraryString(name);
+    if (name.parent!.parent!.isRoot) return classString(name);
 
-    CanonicalName atNode = name.parent;
+    CanonicalName atNode = name.parent!;
     while (!atNode.name.startsWith('@')) {
-      atNode = atNode.parent;
+      atNode = atNode.parent!;
     }
 
     String parent = "";
-    if (atNode.parent.parent.isRoot) {
-      parent = libraryString(atNode.parent);
+    if (atNode.parent!.parent!.isRoot) {
+      parent = libraryString(atNode.parent!);
     } else {
-      parent = classString(atNode.parent);
+      parent = classString(atNode.parent!);
     }
 
     if (name.name == '') return "$parent::$emptyNameString";
@@ -1023,7 +1042,7 @@
     writeWord(getTypeParameterReference(node));
   }
 
-  void writeExpression(Expression node, [int minimumPrecedence]) {
+  void writeExpression(Expression node, [int? minimumPrecedence]) {
     final bool highlight = shouldHighlight(node);
     if (highlight) {
       startHighlight(node);
@@ -1087,9 +1106,10 @@
     writeSpace();
     writeAnnotatedType(node.type, annotator?.annotateField(this, node));
     writeName(getMemberName(node));
-    if (node.initializer != null) {
+    Expression? initializer = node.initializer;
+    if (initializer != null) {
       writeSpaced('=');
-      writeExpression(node.initializer);
+      writeExpression(initializer);
     }
     List<String> features = <String>[];
     if (node.enclosingLibrary.isNonNullableByDefault !=
@@ -1100,10 +1120,10 @@
         features.add("isLegacy");
       }
     }
-    if ((node.enclosingClass == null &&
+    Class? enclosingClass = node.enclosingClass;
+    if ((enclosingClass == null &&
             node.enclosingLibrary.fileUri != node.fileUri) ||
-        (node.enclosingClass != null &&
-            node.enclosingClass.fileUri != node.fileUri)) {
+        (enclosingClass != null && enclosingClass.fileUri != node.fileUri)) {
       features.add(" from ${node.fileUri} ");
     }
     if (features.isNotEmpty) {
@@ -1148,10 +1168,10 @@
         features.add("isLegacy");
       }
     }
-    if ((node.enclosingClass == null &&
+    Class? enclosingClass = node.enclosingClass;
+    if ((enclosingClass == null &&
             node.enclosingLibrary.fileUri != node.fileUri) ||
-        (node.enclosingClass != null &&
-            node.enclosingClass.fileUri != node.fileUri)) {
+        (enclosingClass != null && enclosingClass.fileUri != node.fileUri)) {
       features.add(" from ${node.fileUri} ");
     }
     if (features.isNotEmpty) {
@@ -1163,17 +1183,17 @@
       case ProcedureStubKind.ConcreteForwardingStub:
       case ProcedureStubKind.NoSuchMethodForwarder:
       case ProcedureStubKind.ConcreteMixinStub:
-        writeFunction(node.function, name: getMemberName(node));
+        writeFunction(node.function!, name: getMemberName(node));
         break;
       case ProcedureStubKind.MemberSignature:
       case ProcedureStubKind.AbstractMixinStub:
-        writeFunction(node.function,
+        writeFunction(node.function!,
             name: getMemberName(node), terminateLine: false);
-        if (node.function.body is ReturnStatement) {
+        if (node.function!.body is ReturnStatement) {
           writeSymbol(';');
         }
         writeSymbol(' -> ');
-        writeMemberReferenceFromReference(node.stubTargetReference);
+        writeMemberReferenceFromReference(node.stubTargetReference!);
         endLine();
         break;
     }
@@ -1198,7 +1218,7 @@
     if (features.isNotEmpty) {
       writeWord("/*${features.join(',')}*/");
     }
-    writeFunction(node.function,
+    writeFunction(node.function!,
         name: node.name, initializers: node.initializers);
   }
 
@@ -1210,13 +1230,13 @@
     writeWord('redirecting_factory');
 
     if (node.name != null) {
-      writeName(node.name);
+      writeName(node.name!);
     }
     writeTypeParameterList(node.typeParameters);
     writeParameterList(node.positionalParameters, node.namedParameters,
         node.requiredParameterCount);
     writeSpaced('=');
-    writeMemberReferenceFromReference(node.targetReference);
+    writeMemberReferenceFromReference(node.targetReference!);
     if (node.typeArguments.isNotEmpty) {
       writeSymbol('<');
       writeList(node.typeArguments, writeType);
@@ -1246,12 +1266,12 @@
     writeTypeParameterList(node.typeParameters);
     if (node.isMixinApplication) {
       writeSpaced('=');
-      visitSupertype(node.supertype);
+      visitSupertype(node.supertype!);
       writeSpaced('with');
-      visitSupertype(node.mixedInType);
+      visitSupertype(node.mixedInType!);
     } else if (node.supertype != null) {
       writeSpaced('extends');
-      visitSupertype(node.supertype);
+      visitSupertype(node.supertype!);
     }
     if (node.implementedTypes.isNotEmpty) {
       writeSpaced('implements');
@@ -1297,7 +1317,7 @@
     writeWord(getExtensionName(node));
     writeTypeParameterList(node.typeParameters);
     writeSpaced('on');
-    writeType(node.onType);
+    writeType(node.onType!);
     String endLineString = ' {';
     if (node.enclosingLibrary.fileUri != node.fileUri) {
       endLineString += ' // from ${node.fileUri}';
@@ -1352,18 +1372,20 @@
     writeWord(node.name);
     writeTypeParameterList(node.typeParameters);
     writeSpaced('=');
-    if (node.type is FunctionType) {
-      writeFunctionType(node.type,
+    DartType? type = node.type;
+    if (type is FunctionType) {
+      writeFunctionType(type,
           typedefPositional: node.positionalParameters,
           typedefNamed: node.namedParameters);
     } else {
-      writeNode(node.type);
+      writeNode(type);
     }
     endLine(';');
   }
 
   visitInvalidExpression(InvalidExpression node) {
     writeWord('invalid-expression');
+    // ignore: unnecessary_null_comparison
     if (node.message != null) {
       writeWord('"${escapeString(node.message)}"');
     }
@@ -1415,7 +1437,7 @@
     writeNode(node.arguments);
     if (node.functionType != null) {
       writeSymbol('{');
-      writeType(node.functionType);
+      writeType(node.functionType!);
       writeSymbol('}');
     }
   }
@@ -1530,8 +1552,8 @@
   }
 
   visitLogicalExpression(LogicalExpression node) {
-    int precedence = Precedence
-        .binaryPrecedence[logicalExpressionOperatorToString(node.operatorEnum)];
+    int precedence = Precedence.binaryPrecedence[
+        logicalExpressionOperatorToString(node.operatorEnum)]!;
     writeExpression(node.left, precedence);
     writeSpaced(logicalExpressionOperatorToString(node.operatorEnum));
     writeExpression(node.right, precedence + 1);
@@ -1606,7 +1628,7 @@
       if (!first) {
         writeComma();
       }
-      writeWord('${fieldRef.asField.name.text}');
+      writeWord('${fieldRef.asField.name!.text}');
       writeSymbol(':');
       writeExpression(value);
       first = false;
@@ -1617,9 +1639,10 @@
       }
       write('assert(');
       writeExpression(assert_.condition);
-      if (assert_.message != null) {
+      Expression? message = assert_.message;
+      if (message != null) {
         writeComma();
-        writeExpression(assert_.message);
+        writeExpression(message);
       }
       write(')');
       first = false;
@@ -1692,6 +1715,7 @@
       writeWord('const');
       writeSpace();
     }
+    // ignore: unnecessary_null_comparison
     if (node.typeArgument != null) {
       writeSymbol('<');
       writeType(node.typeArgument);
@@ -1707,6 +1731,7 @@
       writeWord('const');
       writeSpace();
     }
+    // ignore: unnecessary_null_comparison
     if (node.typeArgument != null) {
       writeSymbol('<');
       writeType(node.typeArgument);
@@ -1722,6 +1747,7 @@
       writeWord('const');
       writeSpace();
     }
+    // ignore: unnecessary_null_comparison
     if (node.keyType != null) {
       writeSymbol('<');
       writeList([node.keyType, node.valueType], writeType);
@@ -1791,7 +1817,7 @@
   visitLoadLibrary(LoadLibrary node) {
     writeWord('LoadLibrary');
     writeSymbol('(');
-    writeWord(node.import.name);
+    writeWord(node.import.name!);
     writeSymbol(')');
     state = WORD;
   }
@@ -1799,7 +1825,7 @@
   visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
     writeWord('CheckLibraryIsLoaded');
     writeSymbol('(');
-    writeWord(node.import.name);
+    writeWord(node.import.name!);
     writeSymbol(')');
     state = WORD;
   }
@@ -1816,20 +1842,21 @@
     writeIndentation();
     writeWord(node.isImport ? 'import' : 'export');
     String uriString;
-    if (node.importedLibraryReference?.node != null) {
+    if (node.importedLibraryReference.node != null) {
       uriString = '${node.targetLibrary.importUri}';
     } else {
-      uriString = '${node.importedLibraryReference?.canonicalName?.name}';
+      uriString = '${node.importedLibraryReference.canonicalName?.name}';
     }
     writeWord('"$uriString"');
     if (node.isDeferred) {
       writeWord('deferred');
     }
-    if (node.name != null) {
+    String? name = node.name;
+    if (name != null) {
       writeWord('as');
-      writeWord(node.name);
+      writeWord(name);
     }
-    String last;
+    String? last;
     final String show = 'show';
     final String hide = 'hide';
     if (node.combinators.isNotEmpty) {
@@ -1859,9 +1886,10 @@
 
   visitVariableGet(VariableGet node) {
     writeVariableReference(node.variable);
-    if (node.promotedType != null) {
+    DartType? promotedType = node.promotedType;
+    if (promotedType != null) {
       writeSymbol('{');
-      writeNode(node.promotedType);
+      writeNode(promotedType);
       writeSymbol('}');
       state = WORD;
     }
@@ -1873,7 +1901,7 @@
     writeExpression(node.value);
   }
 
-  void writeInterfaceTarget(Name name, Reference target) {
+  void writeInterfaceTarget(Name name, Reference? target) {
     if (target != null) {
       writeSymbol('{');
       writeMemberReferenceFromReference(target);
@@ -1884,6 +1912,7 @@
   }
 
   void writeStaticType(DartType type) {
+    // ignore: unnecessary_null_comparison
     if (type != null) {
       writeSymbol('{');
       writeType(type);
@@ -2024,9 +2053,10 @@
     writeWord('assert');
     writeSymbol('(');
     writeExpression(node.condition);
-    if (node.message != null) {
+    Expression? message = node.message;
+    if (message != null) {
       writeComma();
-      writeExpression(node.message);
+      writeExpression(message);
     }
     if (!asExpression) {
       endLine(');');
@@ -2075,8 +2105,9 @@
     writeSymbol('(');
     writeList(node.variables, writeVariableDeclaration);
     writeComma(';');
-    if (node.condition != null) {
-      writeExpression(node.condition);
+    Expression? condition = node.condition;
+    if (condition != null) {
+      writeExpression(condition);
     }
     writeComma(';');
     writeList(node.updates, writeExpression);
@@ -2146,19 +2177,21 @@
     writeExpression(node.condition);
     writeSymbol(')');
     writeBody(node.then);
-    if (node.otherwise != null) {
+    Statement? otherwise = node.otherwise;
+    if (otherwise != null) {
       writeIndentation();
       writeWord('else');
-      writeBody(node.otherwise);
+      writeBody(otherwise);
     }
   }
 
   visitReturnStatement(ReturnStatement node) {
     writeIndentation();
     writeWord('return');
-    if (node.expression != null) {
+    Expression? expression = node.expression;
+    if (expression != null) {
       writeSpace();
-      writeExpression(node.expression);
+      writeExpression(expression);
     }
     endLine(';');
   }
@@ -2172,6 +2205,7 @@
 
   visitCatch(Catch node) {
     writeIndentation();
+    // ignore: unnecessary_null_comparison
     if (node.guard != null) {
       writeWord('on');
       writeType(node.guard);
@@ -2179,14 +2213,16 @@
     }
     writeWord('catch');
     writeSymbol('(');
-    if (node.exception != null) {
-      writeVariableDeclaration(node.exception);
+    VariableDeclaration? exception = node.exception;
+    if (exception != null) {
+      writeVariableDeclaration(exception);
     } else {
       writeWord('no-exception-var');
     }
-    if (node.stackTrace != null) {
+    VariableDeclaration? stackTrace = node.stackTrace;
+    if (stackTrace != null) {
       writeComma();
-      writeVariableDeclaration(node.stackTrace);
+      writeVariableDeclaration(stackTrace);
     }
     writeSymbol(')');
     writeBody(node.body);
@@ -2225,7 +2261,7 @@
     writeIndentation();
     writeWord('function');
     if (node.function != null) {
-      writeFunction(node.function, name: getVariableName(node.variable));
+      writeFunction(node.function!, name: getVariableName(node.variable));
     } else {
       writeWord(getVariableName(node.variable));
       endLine('...;');
@@ -2244,16 +2280,19 @@
     writeModifier(node.isGenericCovariantImpl, 'generic-covariant-impl');
     writeModifier(node.isFinal, 'final');
     writeModifier(node.isConst, 'const');
+    // ignore: unnecessary_null_comparison
     if (node.type != null) {
       writeAnnotatedType(node.type, annotator?.annotateVariable(this, node));
     }
+    // ignore: unnecessary_null_comparison
     if (useVarKeyword && !node.isFinal && !node.isConst && node.type == null) {
       writeWord('var');
     }
     writeWord(getVariableName(node));
-    if (node.initializer != null) {
+    Expression? initializer = node.initializer;
+    if (initializer != null) {
       writeSpaced('=');
-      writeExpression(node.initializer);
+      writeExpression(initializer);
     }
   }
 
@@ -2407,14 +2446,15 @@
   visitTypeParameterType(TypeParameterType node) {
     writeTypeParameterReference(node.parameter);
     writeNullability(node.declaredNullability);
-    if (node.promotedBound != null) {
+    DartType? promotedBound = node.promotedBound;
+    if (promotedBound != null) {
       writeSpaced('&');
-      writeType(node.promotedBound);
+      writeType(promotedBound);
 
       writeWord("/* '");
       writeNullability(node.declaredNullability, inComment: true);
       writeWord("' & '");
-      writeDartTypeNullability(node.promotedBound, inComment: true);
+      writeDartTypeNullability(promotedBound, inComment: true);
       writeWord("' = '");
       writeNullability(node.nullability, inComment: true);
       writeWord("' */");
@@ -2434,10 +2474,10 @@
     }
     writeWord(getTypeParameterName(node));
     writeSpaced('extends');
-    writeType(node.bound);
+    writeType(node.bound!);
     if (node.defaultType != null) {
       writeSpaced('=');
-      writeType(node.defaultType);
+      writeType(node.defaultType!);
     }
   }
 
@@ -2488,6 +2528,7 @@
     writeIndentation();
     writeConstantReference(node);
     writeSpaced('=');
+    // ignore: unnecessary_null_comparison
     String text = node.libraryReference != null
         ? '#${node.libraryReference.asLibrary.importUri}::${node.name}'
         : '#${node.name}';
@@ -2556,9 +2597,9 @@
     writeList(node.fieldValues.entries,
         (core.MapEntry<Reference, Constant> entry) {
       if (entry.key.node != null) {
-        writeWord('${entry.key.asField.name.text}');
+        writeWord('${entry.key.asField.name!.text}');
       } else {
-        writeWord('${entry.key.canonicalName.name}');
+        writeWord('${entry.key.canonicalName!.name}');
       }
       writeSymbol(':');
       writeConstantReference(entry.value);
@@ -2636,7 +2677,7 @@
   static const int PRIMARY = 20;
   static const int CALLEE = 21;
 
-  static const Map<String, int> binaryPrecedence = const {
+  static const Map<String?, int> binaryPrecedence = const {
     '&&': LOGICAL_AND,
     '||': LOGICAL_OR,
     '??': LOGICAL_NULL_AWARE,
@@ -2708,7 +2749,7 @@
 
   @override
   int visitLogicalExpression(LogicalExpression node) =>
-      binaryPrecedence[logicalExpressionOperatorToString(node.operatorEnum)];
+      binaryPrecedence[logicalExpressionOperatorToString(node.operatorEnum)]!;
 
   @override
   int visitConditionalExpression(ConditionalExpression node) => CONDITIONAL;
@@ -2862,5 +2903,4 @@
     case ProcedureKind.Factory:
       return 'factory';
   }
-  throw 'illegal ProcedureKind: $kind';
 }
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index 3ababf6..38582df 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -1089,10 +1089,15 @@
 }
 
 TextSerializer<AssertStatement> assertStatementSerializer =
-    Wrapped<Tuple2<Expression, Expression>, AssertStatement>(
-        (a) => Tuple2(a.condition, a.message),
-        (t) => AssertStatement(t.first, message: t.second),
-        Tuple2Serializer(expressionSerializer, Optional(expressionSerializer)));
+    Wrapped<Tuple4<Expression, Expression, int, int>, AssertStatement>(
+        (a) => Tuple4(a.condition, a.message, a.conditionStartOffset,
+            a.conditionEndOffset),
+        (t) => AssertStatement(t.first,
+            message: t.second,
+            conditionStartOffset: t.third,
+            conditionEndOffset: t.fourth),
+        Tuple4Serializer(expressionSerializer, Optional(expressionSerializer),
+            const DartInt(), const DartInt()));
 
 TextSerializer<Block> blockSerializer =
     Wrapped<Tuple2<List<Statement>, Expression>, Block>(
@@ -2102,11 +2107,9 @@
     Wrapped<Tuple4<Name, ExtensionMemberKind, int, CanonicalName>,
             ExtensionMemberDescriptor>(
         (w) => Tuple4(w.name, w.kind, w.flags, w.member.canonicalName),
-        (u) => ExtensionMemberDescriptor()
-          ..name = u.first
-          ..kind = u.second
-          ..flags = u.third
-          ..member = u.fourth.getReference(),
+        (u) => ExtensionMemberDescriptor(
+            name: u.first, kind: u.second, member: u.fourth.getReference())
+          ..flags = u.third,
         Tuple4Serializer(
             nameSerializer,
             extensionMemberKindSerializer,
diff --git a/pkg/kernel/lib/transformations/async.dart b/pkg/kernel/lib/transformations/async.dart
index e8ac7ba..736c9cf 100644
--- a/pkg/kernel/lib/transformations/async.dart
+++ b/pkg/kernel/lib/transformations/async.dart
@@ -177,7 +177,7 @@
   // Transform an expression given an action to transform the children.  For
   // this purposes of the await transformer the children should generally be
   // translated from right to left, in the reverse of evaluation order.
-  Expression transform(Expression expr, void action()) {
+  Expression transformTreeNode(Expression expr, void action()) {
     var shouldName = seenAwait;
 
     // 1. If there is an await in a sibling to the right, emit an assignment to
@@ -208,7 +208,7 @@
 
   // Unary expressions.
   Expression unary(Expression expr) {
-    return transform(expr, () {
+    return transformTreeNode(expr, () {
       expr.transformChildren(this);
     });
   }
@@ -223,7 +223,7 @@
   TreeNode visitThrow(Throw expr) => unary(expr);
 
   TreeNode visitPropertySet(PropertySet expr) {
-    return transform(expr, () {
+    return transformTreeNode(expr, () {
       expr.value = expr.value.accept<TreeNode>(this)..parent = expr;
       expr.receiver = expr.receiver.accept<TreeNode>(this)..parent = expr;
     });
@@ -243,32 +243,32 @@
   }
 
   TreeNode visitMethodInvocation(MethodInvocation expr) {
-    return transform(expr, () {
+    return transformTreeNode(expr, () {
       visitArguments(expr.arguments);
       expr.receiver = expr.receiver.accept<TreeNode>(this)..parent = expr;
     });
   }
 
   TreeNode visitSuperMethodInvocation(SuperMethodInvocation expr) {
-    return transform(expr, () {
+    return transformTreeNode(expr, () {
       visitArguments(expr.arguments);
     });
   }
 
   TreeNode visitStaticInvocation(StaticInvocation expr) {
-    return transform(expr, () {
+    return transformTreeNode(expr, () {
       visitArguments(expr.arguments);
     });
   }
 
   TreeNode visitConstructorInvocation(ConstructorInvocation expr) {
-    return transform(expr, () {
+    return transformTreeNode(expr, () {
       visitArguments(expr.arguments);
     });
   }
 
   TreeNode visitStringConcatenation(StringConcatenation expr) {
-    return transform(expr, () {
+    return transformTreeNode(expr, () {
       var expressions = expr.expressions;
       for (var i = expressions.length - 1; i >= 0; --i) {
         expressions[i] = expressions[i].accept<TreeNode>(this)..parent = expr;
@@ -277,7 +277,7 @@
   }
 
   TreeNode visitListLiteral(ListLiteral expr) {
-    return transform(expr, () {
+    return transformTreeNode(expr, () {
       var expressions = expr.expressions;
       for (var i = expressions.length - 1; i >= 0; --i) {
         expressions[i] = expr.expressions[i].accept<TreeNode>(this)
@@ -287,7 +287,7 @@
   }
 
   TreeNode visitMapLiteral(MapLiteral expr) {
-    return transform(expr, () {
+    return transformTreeNode(expr, () {
       for (var entry in expr.entries.reversed) {
         entry.value = entry.value.accept<TreeNode>(this)..parent = entry;
         entry.key = entry.key.accept<TreeNode>(this)..parent = entry;
@@ -310,7 +310,7 @@
     if (rightStatements.isEmpty) {
       // Easy case: right did not emit any statements.
       seenAwait = shouldName;
-      return transform(expr, () {
+      return transformTreeNode(expr, () {
         expr.left = expr.left.accept<TreeNode>(this)..parent = expr;
         seenAwait = seenAwait || rightAwait;
       });
@@ -391,7 +391,7 @@
     if (thenStatements.isEmpty && otherwiseStatements.isEmpty) {
       // Easy case: neither then nor otherwise emitted any statements.
       seenAwait = shouldName;
-      return transform(expr, () {
+      return transformTreeNode(expr, () {
         expr.condition = expr.condition.accept<TreeNode>(this)..parent = expr;
         seenAwait = seenAwait || thenAwait || otherwiseAwait;
       });
@@ -518,7 +518,7 @@
     } else {
       // The body in `let x = initializer in body` did not contain an await.  We
       // can leave a let expression.
-      return transform(expr, () {
+      return transformTreeNode(expr, () {
         // The body has already been translated.
         expr.body = body..parent = expr;
         variable.initializer = variable.initializer.accept<TreeNode>(this)
@@ -534,7 +534,7 @@
   }
 
   TreeNode visitBlockExpression(BlockExpression expr) {
-    return transform(expr, () {
+    return transformTreeNode(expr, () {
       expr.value = expr.value.accept<TreeNode>(this)..parent = expr;
       List<Statement> body = <Statement>[];
       for (Statement stmt in expr.body.statements.reversed) {
diff --git a/pkg/kernel/lib/transformations/continuation.dart b/pkg/kernel/lib/transformations/continuation.dart
index 0df3e84..24ed26c 100644
--- a/pkg/kernel/lib/transformations/continuation.dart
+++ b/pkg/kernel/lib/transformations/continuation.dart
@@ -296,7 +296,7 @@
     }
 
     ++currentCatchDepth;
-    transformList(node.catches, this, node);
+    transformList(node.catches, node);
     --currentCatchDepth;
     return node;
   }
diff --git a/pkg/kernel/lib/transformations/flags.dart b/pkg/kernel/lib/transformations/flags.dart
index 398afeb..f6d2775 100644
--- a/pkg/kernel/lib/transformations/flags.dart
+++ b/pkg/kernel/lib/transformations/flags.dart
@@ -4,7 +4,6 @@
 
 library kernel.transformations.flags;
 
-// ignore: import_of_legacy_library_into_null_safe
 import '../ast.dart';
 
 /// Flags summarizing the kinds of AST nodes contained in a given member or
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 18c4924..0fb8863 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -4,7 +4,6 @@
 
 library kernel.type_algebra;
 
-// ignore: import_of_legacy_library_into_null_safe
 import 'ast.dart';
 import 'core_types.dart';
 import 'src/replacement_visitor.dart';
@@ -41,7 +40,7 @@
     result[parameter] = const DynamicType();
   }
   for (TypeParameter parameter in host.typeParameters) {
-    result[parameter] = substitute(parameter.bound, result);
+    result[parameter] = substitute(parameter.bound!, result);
   }
   return result;
 }
@@ -121,9 +120,9 @@
     TypeParameter typeParameter = typeParameters[i];
     TypeParameter freshTypeParameter = freshParameters[i];
 
-    freshTypeParameter.bound = substitute(typeParameter.bound, map);
+    freshTypeParameter.bound = substitute(typeParameter.bound!, map);
     freshTypeParameter.defaultType = typeParameter.defaultType != null
-        ? substitute(typeParameter.defaultType, map)
+        ? substitute(typeParameter.defaultType!, map)
         : null;
     freshTypeParameter.variance =
         typeParameter.isLegacyCovariant ? null : typeParameter.variance;
@@ -148,7 +147,7 @@
         requiredParameterCount: type.requiredParameterCount,
         typedefType: type.typedefType == null
             ? null
-            : substitute(type.typedefType) as TypedefType);
+            : substitute(type.typedefType!) as TypedefType);
   }
 
   DartType substitute(DartType type) => substitution.substituteType(type);
@@ -250,7 +249,7 @@
       upper[parameter] = const DynamicType();
     }
     for (TypeParameter parameter in class_.typeParameters) {
-      upper[parameter] = substitute(parameter.bound, upper);
+      upper[parameter] = substitute(parameter.bound!, upper);
     }
     return fromUpperAndLowerBounds(upper, {});
   }
@@ -384,9 +383,9 @@
     TypeParameter fresh = new TypeParameter(node.name);
     TypeParameterType typeParameterType = substitution[node] =
         new TypeParameterType.forAlphaRenaming(node, fresh);
-    fresh.bound = visit(node.bound);
+    fresh.bound = visit(node.bound!);
     if (node.defaultType != null) {
-      fresh.defaultType = visit(node.defaultType);
+      fresh.defaultType = visit(node.defaultType!);
     }
     // If the bound was changed from substituting the bound we need to update
     // implicit nullability to be based on the new bound. If the bound wasn't
@@ -561,7 +560,7 @@
     DartType returnType = inner.visit(node.returnType);
     TypedefType? typedefType = node.typedefType == null
         ? null
-        : inner.visit(node.typedefType) as TypedefType;
+        : inner.visit(node.typedefType!) as TypedefType;
     if (this.useCounter == before) return node;
     return new FunctionType(positionalParameters, returnType, node.nullability,
         namedParameters: namedParameters,
@@ -699,9 +698,9 @@
 
   bool handleTypeParameter(TypeParameter node) {
     assert(!variables.contains(node));
-    if (node.bound.accept(this)) return true;
+    if (node.bound!.accept(this)) return true;
     if (node.defaultType == null) return false;
-    return node.defaultType.accept(this);
+    return node.defaultType!.accept(this);
   }
 }
 
@@ -755,9 +754,9 @@
 
   bool handleTypeParameter(TypeParameter node) {
     assert(variables.contains(node));
-    if (node.bound.accept(this)) return true;
+    if (node.bound!.accept(this)) return true;
     if (node.defaultType == null) return false;
-    return node.defaultType.accept(this);
+    return node.defaultType!.accept(this);
   }
 }
 
@@ -811,9 +810,9 @@
 
   bool handleTypeParameter(TypeParameter node) {
     assert(variables.contains(node));
-    if (node.bound.accept(this)) return true;
+    if (node.bound!.accept(this)) return true;
     if (node.defaultType == null) return false;
-    return node.defaultType.accept(this);
+    return node.defaultType!.accept(this);
   }
 }
 
@@ -1057,7 +1056,7 @@
     //  - The greatest closure of `S` with respect to `L` is `Function`
     if (node.typeParameters.isNotEmpty) {
       for (TypeParameter typeParameter in node.typeParameters) {
-        if (containsTypeVariable(typeParameter.bound, eliminationTargets,
+        if (containsTypeVariable(typeParameter.bound!, eliminationTargets,
             unhandledTypeHandler: unhandledTypeHandler)) {
           return getFunctionReplacement(variance);
         }
diff --git a/pkg/kernel/lib/type_environment.dart b/pkg/kernel/lib/type_environment.dart
index da45c08..c8789ae 100644
--- a/pkg/kernel/lib/type_environment.dart
+++ b/pkg/kernel/lib/type_environment.dart
@@ -4,7 +4,6 @@
 
 library kernel.type_environment;
 
-// ignore: import_of_legacy_library_into_null_safe
 import 'ast.dart';
 import 'class_hierarchy.dart';
 import 'core_types.dart';
@@ -115,8 +114,7 @@
   DartType _resolveTypeParameterType(DartType type) {
     while (type is TypeParameterType) {
       TypeParameterType typeParameterType = type;
-      type =
-          typeParameterType.promotedBound ?? typeParameterType.parameter.bound;
+      type = typeParameterType.bound;
     }
     return type;
   }
@@ -148,13 +146,13 @@
   bool isSpecialCasedBinaryOperator(Procedure member,
       {bool isNonNullableByDefault: false}) {
     if (isNonNullableByDefault) {
-      Class class_ = member.enclosingClass;
+      Class? class_ = member.enclosingClass;
       // TODO(johnniwinther): Do we need to recognize backend implementation
       //  methods?
       if (class_ == coreTypes.intClass ||
           class_ == coreTypes.numClass ||
           class_ == coreTypes.doubleClass) {
-        String name = member.name.text;
+        String name = member.name!.text;
         return name == '+' ||
             name == '-' ||
             name == '*' ||
@@ -162,9 +160,9 @@
             name == '%';
       }
     } else {
-      Class class_ = member.enclosingClass;
+      Class? class_ = member.enclosingClass;
       if (class_ == coreTypes.intClass || class_ == coreTypes.numClass) {
-        String name = member.name.text;
+        String name = member.name!.text;
         return name == '+' ||
             name == '-' ||
             name == '*' ||
@@ -180,9 +178,9 @@
   bool isSpecialCasedTernaryOperator(Procedure member,
       {bool isNonNullableByDefault: false}) {
     if (isNonNullableByDefault) {
-      Class class_ = member.enclosingClass;
+      Class? class_ = member.enclosingClass;
       if (class_ == coreTypes.intClass || class_ == coreTypes.numClass) {
-        String name = member.name.text;
+        String name = member.name!.text;
         return name == 'clamp';
       }
     }
@@ -751,7 +749,7 @@
         "No member currently associated with StaticTypeContext.");
     return _currentMember?.enclosingClass?.getThisType(
         typeEnvironment.coreTypes,
-        _currentMember?.enclosingLibrary.nonNullable);
+        _currentMember!.enclosingLibrary.nonNullable);
   }
 
   @override
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index 93a7b3a..13e7f14 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -4,10 +4,8 @@
 
 library kernel.ast.visitor;
 
-import 'dart:core' hide MapEntry;
 import 'dart:collection';
 
-// ignore: import_of_legacy_library_into_null_safe
 import 'ast.dart';
 
 abstract class ExpressionVisitor<R> {
@@ -127,6 +125,20 @@
   }
 }
 
+abstract class MemberVisitor1<R, A> {
+  const MemberVisitor1();
+
+  R defaultMember(Member node, A arg);
+
+  R visitConstructor(Constructor node, A arg) => defaultMember(node, arg);
+  R visitProcedure(Procedure node, A arg) => defaultMember(node, arg);
+  R visitField(Field node, A arg) => defaultMember(node, arg);
+  R visitRedirectingFactoryConstructor(
+      RedirectingFactoryConstructor node, A arg) {
+    return defaultMember(node, arg);
+  }
+}
+
 abstract class InitializerVisitor<R> {
   const InitializerVisitor();
 
@@ -142,6 +154,25 @@
   R visitAssertInitializer(AssertInitializer node) => defaultInitializer(node);
 }
 
+abstract class InitializerVisitor1<R, A> {
+  const InitializerVisitor1();
+
+  R defaultInitializer(Initializer node, A arg);
+
+  R visitInvalidInitializer(InvalidInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+  R visitFieldInitializer(FieldInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+  R visitSuperInitializer(SuperInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+  R visitRedirectingInitializer(RedirectingInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+  R visitLocalInitializer(LocalInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+  R visitAssertInitializer(AssertInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+}
+
 abstract class TreeVisitor<R>
     implements
         ExpressionVisitor<R>,
@@ -288,6 +319,195 @@
   R visitComponent(Component node) => defaultTreeNode(node);
 }
 
+abstract class TreeVisitor1<R, A>
+    implements
+        ExpressionVisitor1<R, A>,
+        StatementVisitor1<R, A>,
+        MemberVisitor1<R, A>,
+        InitializerVisitor1<R, A> {
+  const TreeVisitor1();
+
+  R defaultTreeNode(TreeNode node, A arg);
+
+  // Expressions
+  R defaultExpression(Expression node, A arg) => defaultTreeNode(node, arg);
+  R defaultBasicLiteral(BasicLiteral node, A arg) =>
+      defaultExpression(node, arg);
+  R visitInvalidExpression(InvalidExpression node, A arg) =>
+      defaultExpression(node, arg);
+  R visitVariableGet(VariableGet node, A arg) => defaultExpression(node, arg);
+  R visitVariableSet(VariableSet node, A arg) => defaultExpression(node, arg);
+  R visitDynamicGet(DynamicGet node, A arg) => defaultExpression(node, arg);
+  R visitDynamicSet(DynamicSet node, A arg) => defaultExpression(node, arg);
+  R visitFunctionTearOff(FunctionTearOff node, A arg) =>
+      defaultExpression(node, arg);
+  R visitInstanceGet(InstanceGet node, A arg) => defaultExpression(node, arg);
+  R visitInstanceSet(InstanceSet node, A arg) => defaultExpression(node, arg);
+  R visitInstanceTearOff(InstanceTearOff node, A arg) =>
+      defaultExpression(node, arg);
+  R visitPropertyGet(PropertyGet node, A arg) => defaultExpression(node, arg);
+  R visitPropertySet(PropertySet node, A arg) => defaultExpression(node, arg);
+  R visitSuperPropertyGet(SuperPropertyGet node, A arg) =>
+      defaultExpression(node, arg);
+  R visitSuperPropertySet(SuperPropertySet node, A arg) =>
+      defaultExpression(node, arg);
+  R visitStaticGet(StaticGet node, A arg) => defaultExpression(node, arg);
+  R visitStaticSet(StaticSet node, A arg) => defaultExpression(node, arg);
+  R visitStaticTearOff(StaticTearOff node, A arg) =>
+      defaultExpression(node, arg);
+  R visitLocalFunctionInvocation(LocalFunctionInvocation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitDynamicInvocation(DynamicInvocation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitFunctionInvocation(FunctionInvocation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitInstanceInvocation(InstanceInvocation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitEqualsNull(EqualsNull node, A arg) => defaultExpression(node, arg);
+  R visitEqualsCall(EqualsCall node, A arg) => defaultExpression(node, arg);
+  R visitMethodInvocation(MethodInvocation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitSuperMethodInvocation(SuperMethodInvocation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitStaticInvocation(StaticInvocation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitConstructorInvocation(ConstructorInvocation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitNot(Not node, A arg) => defaultExpression(node, arg);
+  R visitNullCheck(NullCheck node, A arg) => defaultExpression(node, arg);
+  R visitLogicalExpression(LogicalExpression node, A arg) =>
+      defaultExpression(node, arg);
+  R visitConditionalExpression(ConditionalExpression node, A arg) =>
+      defaultExpression(node, arg);
+  R visitStringConcatenation(StringConcatenation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitListConcatenation(ListConcatenation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitSetConcatenation(SetConcatenation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitMapConcatenation(MapConcatenation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitInstanceCreation(InstanceCreation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitFileUriExpression(FileUriExpression node, A arg) =>
+      defaultExpression(node, arg);
+  R visitIsExpression(IsExpression node, A arg) => defaultExpression(node, arg);
+  R visitAsExpression(AsExpression node, A arg) => defaultExpression(node, arg);
+  R visitSymbolLiteral(SymbolLiteral node, A arg) =>
+      defaultExpression(node, arg);
+  R visitTypeLiteral(TypeLiteral node, A arg) => defaultExpression(node, arg);
+  R visitThisExpression(ThisExpression node, A arg) =>
+      defaultExpression(node, arg);
+  R visitRethrow(Rethrow node, A arg) => defaultExpression(node, arg);
+  R visitThrow(Throw node, A arg) => defaultExpression(node, arg);
+  R visitListLiteral(ListLiteral node, A arg) => defaultExpression(node, arg);
+  R visitSetLiteral(SetLiteral node, A arg) => defaultExpression(node, arg);
+  R visitMapLiteral(MapLiteral node, A arg) => defaultExpression(node, arg);
+  R visitAwaitExpression(AwaitExpression node, A arg) =>
+      defaultExpression(node, arg);
+  R visitFunctionExpression(FunctionExpression node, A arg) =>
+      defaultExpression(node, arg);
+  R visitConstantExpression(ConstantExpression node, A arg) =>
+      defaultExpression(node, arg);
+  R visitStringLiteral(StringLiteral node, A arg) =>
+      defaultBasicLiteral(node, arg);
+  R visitIntLiteral(IntLiteral node, A arg) => defaultBasicLiteral(node, arg);
+  R visitDoubleLiteral(DoubleLiteral node, A arg) =>
+      defaultBasicLiteral(node, arg);
+  R visitBoolLiteral(BoolLiteral node, A arg) => defaultBasicLiteral(node, arg);
+  R visitNullLiteral(NullLiteral node, A arg) => defaultBasicLiteral(node, arg);
+  R visitLet(Let node, A arg) => defaultExpression(node, arg);
+  R visitBlockExpression(BlockExpression node, A arg) =>
+      defaultExpression(node, arg);
+  R visitInstantiation(Instantiation node, A arg) =>
+      defaultExpression(node, arg);
+  R visitLoadLibrary(LoadLibrary node, A arg) => defaultExpression(node, arg);
+  R visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node, A arg) =>
+      defaultExpression(node, arg);
+
+  // Statements
+  R defaultStatement(Statement node, A arg) => defaultTreeNode(node, arg);
+  R visitExpressionStatement(ExpressionStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitBlock(Block node, A arg) => defaultStatement(node, arg);
+  R visitAssertBlock(AssertBlock node, A arg) => defaultStatement(node, arg);
+  R visitEmptyStatement(EmptyStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitAssertStatement(AssertStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitLabeledStatement(LabeledStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitBreakStatement(BreakStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitWhileStatement(WhileStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitDoStatement(DoStatement node, A arg) => defaultStatement(node, arg);
+  R visitForStatement(ForStatement node, A arg) => defaultStatement(node, arg);
+  R visitForInStatement(ForInStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitSwitchStatement(SwitchStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitContinueSwitchStatement(ContinueSwitchStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitIfStatement(IfStatement node, A arg) => defaultStatement(node, arg);
+  R visitReturnStatement(ReturnStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitTryCatch(TryCatch node, A arg) => defaultStatement(node, arg);
+  R visitTryFinally(TryFinally node, A arg) => defaultStatement(node, arg);
+  R visitYieldStatement(YieldStatement node, A arg) =>
+      defaultStatement(node, arg);
+  R visitVariableDeclaration(VariableDeclaration node, A arg) =>
+      defaultStatement(node, arg);
+  R visitFunctionDeclaration(FunctionDeclaration node, A arg) =>
+      defaultStatement(node, arg);
+
+  // Members
+  R defaultMember(Member node, A arg) => defaultTreeNode(node, arg);
+  R visitConstructor(Constructor node, A arg) => defaultMember(node, arg);
+  R visitProcedure(Procedure node, A arg) => defaultMember(node, arg);
+  R visitField(Field node, A arg) => defaultMember(node, arg);
+  R visitRedirectingFactoryConstructor(
+      RedirectingFactoryConstructor node, A arg) {
+    return defaultMember(node, arg);
+  }
+
+  // Classes
+  R visitClass(Class node, A arg) => defaultTreeNode(node, arg);
+  R visitExtension(Extension node, A arg) => defaultTreeNode(node, arg);
+
+  // Initializers
+  R defaultInitializer(Initializer node, A arg) => defaultTreeNode(node, arg);
+  R visitInvalidInitializer(InvalidInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+  R visitFieldInitializer(FieldInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+  R visitSuperInitializer(SuperInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+  R visitRedirectingInitializer(RedirectingInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+  R visitLocalInitializer(LocalInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+  R visitAssertInitializer(AssertInitializer node, A arg) =>
+      defaultInitializer(node, arg);
+
+  // Other tree nodes
+  R visitLibrary(Library node, A arg) => defaultTreeNode(node, arg);
+  R visitLibraryDependency(LibraryDependency node, A arg) =>
+      defaultTreeNode(node, arg);
+  R visitCombinator(Combinator node, A arg) => defaultTreeNode(node, arg);
+  R visitLibraryPart(LibraryPart node, A arg) => defaultTreeNode(node, arg);
+  R visitTypedef(Typedef node, A arg) => defaultTreeNode(node, arg);
+  R visitTypeParameter(TypeParameter node, A arg) => defaultTreeNode(node, arg);
+  R visitFunctionNode(FunctionNode node, A arg) => defaultTreeNode(node, arg);
+  R visitArguments(Arguments node, A arg) => defaultTreeNode(node, arg);
+  R visitNamedExpression(NamedExpression node, A arg) =>
+      defaultTreeNode(node, arg);
+  R visitSwitchCase(SwitchCase node, A arg) => defaultTreeNode(node, arg);
+  R visitCatch(Catch node, A arg) => defaultTreeNode(node, arg);
+  R visitMapEntry(MapEntry node, A arg) => defaultTreeNode(node, arg);
+  R visitComponent(Component node, A arg) => defaultTreeNode(node, arg);
+}
+
 abstract class DartTypeVisitor<R> {
   const DartTypeVisitor();
 
@@ -776,6 +996,54 @@
 class Transformer extends TreeVisitor<TreeNode> {
   const Transformer();
 
+  T transform<T extends TreeNode>(T node) {
+    T result = node.accept<TreeNode>(this) as T;
+    assert(
+        // ignore: unnecessary_null_comparison
+        result != null,
+        'Attempting to remove ${node} (${node.runtimeType}) '
+        'in transformer.');
+    return result;
+  }
+
+  void transformDartTypeList(List<DartType> nodes) {
+    for (int i = 0; i < nodes.length; ++i) {
+      DartType result = visitDartType(nodes[i]);
+      assert(
+          // ignore: unnecessary_null_comparison
+          result != null,
+          'Attempting to remove ${nodes[i]} (${nodes[i].runtimeType}) '
+          'in transformer.');
+      nodes[i] = result;
+    }
+  }
+
+  void transformSupertypeList(List<Supertype> nodes) {
+    for (int i = 0; i < nodes.length; ++i) {
+      Supertype result = visitSupertype(nodes[i]);
+      assert(
+          // ignore: unnecessary_null_comparison
+          result != null,
+          'Attempting to remove ${nodes[i]} (${nodes[i].runtimeType}) '
+          'in transformer.');
+      nodes[i] = result;
+    }
+  }
+
+  void transformList<T extends TreeNode>(List<T> nodes, TreeNode parent) {
+    for (int i = 0; i < nodes.length; ++i) {
+      T result = transform(nodes[i]);
+      assert(
+          // ignore: unnecessary_null_comparison
+          result != null,
+          'Attempting to remove ${nodes[i]} (${nodes[i].runtimeType}) '
+          'in transformer.');
+      // ignore: invalid_null_aware_operator
+      result.parent = parent;
+      nodes[i] = result;
+    }
+  }
+
   /// Replaces a use of a type.
   ///
   /// By default, recursion stops at this point.
@@ -791,6 +1059,362 @@
   }
 }
 
+/// Transformer that recursively rewrites each node in tree and supports removal
+/// of nodes.
+///
+/// Visit methods should return a new node, the visited node (possibly
+/// mutated), any node from the visited node's subtree, or the provided
+/// removal sentinel, if non-null.
+///
+/// To support removal of nodes during traversal, while enforcing nullability
+/// invariants, this visitor takes an argument, the removal sentinel. If a
+/// node is visited in a context where it can be removed, for instance in a
+/// list or as an optional child of its parent, a non-null sentinel value is
+/// provided, and this value can be returned to signal to the caller that the
+/// visited node should be removed. If the sentinel value is `null`, the node
+/// cannot be removed from its context, in which case the node itself or a new
+/// non-null node must be returned, possibly a sentinel value specific to the
+/// particular visitor.
+///
+/// For instance
+///
+///     class AssertRemover extends RemovingTransformer {
+///        @override
+///        TreeNode visitAssertStatement(
+///            AssertStatement node,
+///            TreeNode? removalSentinel) {
+///          return removalSentinel ?? new EmptyStatement();
+///        }
+///
+///        @override
+///        TreeNode visitIfStatement(
+///            IfStatement node,
+///            TreeNode? removalSentinel) {
+///          node.transformOrRemoveChildren(this);
+///          if (node.then is EmptyStatement) {
+///            if (node.otherwise != null) {
+///              return new IfStatement(
+///                  new Not(node.condition), node.otherwise);
+///            } else {
+///              return removalSentinel ?? new EmptyStatement();
+///            }
+///          }
+///          return node;
+///        }
+///     }
+///
+/// Each subclass is responsible for ensuring that the AST remains a tree.
+///
+/// For example, the following transformer replaces every occurrence of
+/// `!(x && y)` with `(!x || !y)`:
+///
+///     class NegationSinker extends RemovingTransformer {
+///       @override
+///       Node visitNot(Not node) {
+///         var operand = node.operand.accept(this); // Remember to visit.
+///         if (operand is LogicalExpression && operand.operator == '&&') {
+///           return new LogicalExpression(
+///             new Not(operand.left),
+///             '||',
+///             new Not(operand.right));
+///         }
+///         return node;
+///       }
+///     }
+///
+class RemovingTransformer extends TreeVisitor1<TreeNode, TreeNode?> {
+  const RemovingTransformer();
+
+  /// Visits [node], returning the transformation result.
+  ///
+  /// The transformation cannot result in `null`.
+  T transform<T extends TreeNode>(T node) {
+    return node.accept1<TreeNode, TreeNode?>(this, cannotRemoveSentinel) as T;
+  }
+
+  /// Visits [node], returning the transformation result. Removal of [node] is
+  /// supported with `null` as the result.
+  ///
+  /// This is convenience method for calling [transformOrRemove] with removal
+  /// sentinel for [Expression] nodes.
+  Expression? transformOrRemoveExpression(Expression node) {
+    return transformOrRemove(node, dummyExpression);
+  }
+
+  /// Visits [node], returning the transformation result. Removal of [node] is
+  /// supported with `null` as the result.
+  ///
+  /// This is convenience method for calling [transformOrRemove] with removal
+  /// sentinel for [Statement] nodes.
+  Statement? transformOrRemoveStatement(Statement node) {
+    return transformOrRemove(node, dummyStatement);
+  }
+
+  /// Visits [node], returning the transformation result. Removal of [node] is
+  /// supported with `null` as the result.
+  ///
+  /// This is convenience method for calling [transformOrRemove] with removal
+  /// sentinel for [VariableDeclaration] nodes.
+  VariableDeclaration? transformOrRemoveVariableDeclaration(
+      VariableDeclaration node) {
+    return transformOrRemove(node, dummyVariableDeclaration);
+  }
+
+  /// Visits [node] using [removalSentinel] as the removal sentinel.
+  ///
+  /// If [removalSentinel] is the result of visiting [node], `null` is returned.
+  /// Otherwise the result is returned.
+  T? transformOrRemove<T extends TreeNode>(T node, T? removalSentinel) {
+    T result = node.accept1<TreeNode, TreeNode?>(this, removalSentinel) as T;
+    if (identical(result, removalSentinel)) {
+      return null;
+    } else {
+      return result;
+    }
+  }
+
+  /// Transforms or removes [DartType] nodes in [nodes].
+  void transformDartTypeList(List<DartType> nodes) {
+    int storeIndex = 0;
+    for (int i = 0; i < nodes.length; ++i) {
+      DartType result = visitDartType(nodes[i], dummyDartType);
+      if (!identical(result, dummyDartType)) {
+        nodes[storeIndex] = result;
+        ++storeIndex;
+      }
+    }
+    if (storeIndex < nodes.length) {
+      nodes.length = storeIndex;
+    }
+  }
+
+  /// Transforms or removes [Supertype] nodes in [nodes].
+  void transformSupertypeList(List<Supertype> nodes) {
+    int storeIndex = 0;
+    for (int i = 0; i < nodes.length; ++i) {
+      Supertype result = visitSupertype(nodes[i], dummySupertype);
+      if (!identical(result, dummySupertype)) {
+        nodes[storeIndex] = result;
+        ++storeIndex;
+      }
+    }
+    if (storeIndex < nodes.length) {
+      nodes.length = storeIndex;
+    }
+  }
+
+  /// Transforms or removes [Library] nodes in [nodes] as children of [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Library] nodes.
+  void transformLibraryList(List<Library> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyLibrary);
+  }
+
+  /// Transforms or removes [LibraryDependency] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [LibraryDependency] nodes.
+  void transformLibraryDependencyList(
+      List<LibraryDependency> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyLibraryDependency);
+  }
+
+  /// Transforms or removes [Combinator] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Combinator] nodes.
+  void transformCombinatorList(List<Combinator> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyCombinator);
+  }
+
+  /// Transforms or removes [LibraryPart] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [LibraryPart] nodes.
+  void transformLibraryPartList(List<LibraryPart> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyLibraryPart);
+  }
+
+  /// Transforms or removes [Class] nodes in [nodes] as children of [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Class] nodes.
+  void transformClassList(List<Class> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyClass);
+  }
+
+  /// Transforms or removes [Extension] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Extension] nodes.
+  void transformExtensionList(List<Extension> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyExtension);
+  }
+
+  /// Transforms or removes [Constructor] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Constructor] nodes.
+  void transformConstructorList(List<Constructor> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyConstructor);
+  }
+
+  /// Transforms or removes [Procedure] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Procedure] nodes.
+  void transformProcedureList(List<Procedure> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyProcedure);
+  }
+
+  /// Transforms or removes [Field] nodes in [nodes] as children of [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Field] nodes.
+  void transformFieldList(List<Field> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyField);
+  }
+
+  /// Transforms or removes [RedirectingFactoryConstructor] nodes in [nodes] as
+  /// children of [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [RedirectingFactoryConstructor] nodes.
+  void transformRedirectingFactoryConstructorList(
+      List<RedirectingFactoryConstructor> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyRedirectingFactoryConstructor);
+  }
+
+  /// Transforms or removes [Typedef] nodes in [nodes] as children of [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Typedef] nodes.
+  void transformTypedefList(List<Typedef> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyTypedef);
+  }
+
+  /// Transforms or removes [Initializer] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Initializer] nodes.
+  void transformInitializerList(List<Initializer> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyInitializer);
+  }
+
+  /// Transforms or removes [Expression] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Expression] nodes.
+  void transformExpressionList(List<Expression> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyExpression);
+  }
+
+  /// Transforms or removes [NamedExpression] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [NamedExpression] nodes.
+  void transformNamedExpressionList(
+      List<NamedExpression> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyNamedExpression);
+  }
+
+  /// Transforms or removes [MapEntry] nodes in [nodes] as children of [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [MapEntry] nodes.
+  void transformMapEntryList(List<MapEntry> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyMapEntry);
+  }
+
+  /// Transforms or removes [Statement] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Statement] nodes.
+  void transformStatementList(List<Statement> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyStatement);
+  }
+
+  /// Transforms or removes [SwitchCase] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [SwitchCase] nodes.
+  void transformSwitchCaseList(List<SwitchCase> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummySwitchCase);
+  }
+
+  /// Transforms or removes [Catch] nodes in [nodes] as children of [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [Catch] nodes.
+  void transformCatchList(List<Catch> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyCatch);
+  }
+
+  /// Transforms or removes [TypeParameter] nodes in [nodes] as children of
+  /// [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [TypeParameter] nodes.
+  void transformTypeParameterList(List<TypeParameter> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyTypeParameter);
+  }
+
+  /// Transforms or removes [VariableDeclaration] nodes in [nodes] as children
+  /// of [parent].
+  ///
+  /// This is convenience method for calling [transformList] with removal
+  /// sentinel for [VariableDeclaration] nodes.
+  void transformVariableDeclarationList(
+      List<VariableDeclaration> nodes, TreeNode parent) {
+    transformList(nodes, parent, dummyVariableDeclaration);
+  }
+
+  /// Transforms or removes [T] nodes in [nodes] as children of [parent] by
+  /// calling [transformOrRemove] using [removalSentinel] as the removal
+  /// sentinel.
+  void transformList<T extends TreeNode>(
+      List<T> nodes, TreeNode parent, T removalSentinel) {
+    int storeIndex = 0;
+    for (int i = 0; i < nodes.length; ++i) {
+      T? result = transformOrRemove(nodes[i], removalSentinel);
+      if (result != null) {
+        nodes[storeIndex] = result;
+        result.parent = parent;
+        ++storeIndex;
+      }
+    }
+    if (storeIndex < nodes.length) {
+      nodes.length = storeIndex;
+    }
+  }
+
+  /// Replaces a use of a type.
+  ///
+  /// By default, recursion stops at this point.
+  DartType visitDartType(DartType node, DartType? removalSentinel) => node;
+
+  Constant visitConstant(Constant node, Constant? removalSentinel) => node;
+
+  Supertype visitSupertype(Supertype node, Supertype? removalSentinel) => node;
+
+  TreeNode defaultTreeNode(TreeNode node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    return node;
+  }
+}
+
 abstract class ExpressionVisitor1<R, T> {
   const ExpressionVisitor1();
 
diff --git a/pkg/kernel/test/dart_type_equivalence_test.dart b/pkg/kernel/test/dart_type_equivalence_test.dart
index aeb980e..acf4b96 100644
--- a/pkg/kernel/test/dart_type_equivalence_test.dart
+++ b/pkg/kernel/test/dart_type_equivalence_test.dart
@@ -6,7 +6,7 @@
 
 import "package:expect/expect.dart" show Expect;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/src/dart_type_equivalence.dart';
 import 'package:kernel/testing/type_parser_environment.dart';
 
diff --git a/pkg/kernel/test/flatten_test.dart b/pkg/kernel/test/flatten_test.dart
index 00c707a..2dd50b8 100644
--- a/pkg/kernel/test/flatten_test.dart
+++ b/pkg/kernel/test/flatten_test.dart
@@ -6,7 +6,7 @@
 
 import "package:expect/expect.dart" show Expect;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/testing/type_parser_environment.dart';
 import 'package:kernel/type_environment.dart';
diff --git a/pkg/kernel/test/future_value_type_test.dart b/pkg/kernel/test/future_value_type_test.dart
index 5eed73f..f256cfe 100644
--- a/pkg/kernel/test/future_value_type_test.dart
+++ b/pkg/kernel/test/future_value_type_test.dart
@@ -6,7 +6,7 @@
 
 import "package:expect/expect.dart" show Expect;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/src/future_value_type.dart';
 import 'package:kernel/testing/type_parser_environment.dart';
 
diff --git a/pkg/kernel/test/legacy_erasure_test.dart b/pkg/kernel/test/legacy_erasure_test.dart
index f62eba0..4e14b3b 100644
--- a/pkg/kernel/test/legacy_erasure_test.dart
+++ b/pkg/kernel/test/legacy_erasure_test.dart
@@ -6,7 +6,7 @@
 
 import "package:expect/expect.dart" show Expect;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/src/legacy_erasure.dart';
 import 'package:kernel/testing/type_parser_environment.dart';
 
diff --git a/pkg/kernel/test/nnbd_top_merge_test.dart b/pkg/kernel/test/nnbd_top_merge_test.dart
index 1296889..73d07d2 100644
--- a/pkg/kernel/test/nnbd_top_merge_test.dart
+++ b/pkg/kernel/test/nnbd_top_merge_test.dart
@@ -6,7 +6,7 @@
 
 import "package:expect/expect.dart" show Expect;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/src/nnbd_top_merge.dart';
 import 'package:kernel/testing/type_parser_environment.dart';
 
diff --git a/pkg/kernel/test/non_null_test.dart b/pkg/kernel/test/non_null_test.dart
index c4f2570..ef3b433 100644
--- a/pkg/kernel/test/non_null_test.dart
+++ b/pkg/kernel/test/non_null_test.dart
@@ -6,7 +6,7 @@
 
 import "package:expect/expect.dart" show Expect;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/src/non_null.dart';
 import 'package:kernel/testing/type_parser_environment.dart';
 
diff --git a/pkg/kernel/test/norm_test.dart b/pkg/kernel/test/norm_test.dart
index 5fe8429..0f2cd38 100644
--- a/pkg/kernel/test/norm_test.dart
+++ b/pkg/kernel/test/norm_test.dart
@@ -6,7 +6,7 @@
 
 import "package:expect/expect.dart" show Expect;
 
-import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/ast.dart';
 import 'package:kernel/src/norm.dart';
 import 'package:kernel/testing/type_parser_environment.dart';
 
diff --git a/pkg/kernel/test/verify_test.dart b/pkg/kernel/test/verify_test.dart
index 7b6a238..097200d 100644
--- a/pkg/kernel/test/verify_test.dart
+++ b/pkg/kernel/test/verify_test.dart
@@ -227,7 +227,7 @@
   negative1Test(
     'Dangling interface type',
     (TestHarness test) {
-      Class orphan = new Class();
+      Class orphan = new Class(name: 'Class');
       test.addNode(
           new TypeLiteral(new InterfaceType(orphan, Nullability.legacy)));
       return orphan;
@@ -264,27 +264,6 @@
       test.addNode(procedure);
     },
   );
-  simpleNegativeTest(
-    'StaticGet without target',
-    "StaticGet without target.",
-    (TestHarness test) {
-      test.addNode(StaticGet(null));
-    },
-  );
-  simpleNegativeTest(
-    'StaticSet without target',
-    "StaticSet without target.",
-    (TestHarness test) {
-      test.addNode(StaticSet(null, new NullLiteral()));
-    },
-  );
-  simpleNegativeTest(
-    'StaticInvocation without target',
-    "StaticInvocation without target.",
-    (TestHarness test) {
-      test.addNode(StaticInvocation(null, new Arguments.empty()));
-    },
-  );
   positiveTest(
     'Correct StaticInvocation',
     (TestHarness test) {
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index e08f278..d91154e 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -3,8 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 library vm.target.vm;
 
-import 'dart:core' hide MapEntry;
-
 import 'package:kernel/ast.dart';
 import 'package:kernel/clone.dart';
 import 'package:kernel/class_hierarchy.dart';
diff --git a/pkg/vm/lib/transformations/mixin_deduplication.dart b/pkg/vm/lib/transformations/mixin_deduplication.dart
index 31481a8..dce3d1b 100644
--- a/pkg/vm/lib/transformations/mixin_deduplication.dart
+++ b/pkg/vm/lib/transformations/mixin_deduplication.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.12
+
 library vm.transformations.mixin_deduplication;
 
 import 'package:kernel/ast.dart';
@@ -13,7 +15,8 @@
 
   // Deduplicate mixins and re-resolve super initializers.
   // (this is a shallow transformation)
-  component.libraries.forEach(deduplicateMixins.visitLibrary);
+  component.libraries
+      .forEach((library) => deduplicateMixins.visitLibrary(library, null));
 
   // Do a deep transformation to update references to the removed mixin
   // application classes in the interface targets and types.
@@ -83,29 +86,30 @@
   }
 }
 
-class DeduplicateMixinsTransformer extends Transformer {
+class DeduplicateMixinsTransformer extends RemovingTransformer {
   final _canonicalMixins = new Map<_DeduplicateMixinKey, Class>();
   final _duplicatedMixins = new Map<Class, Class>();
 
   @override
-  TreeNode visitLibrary(Library node) {
-    transformList(node.classes, this, node);
+  TreeNode visitLibrary(Library node, TreeNode? removalSentinel) {
+    transformClassList(node.classes, node);
     return node;
   }
 
   @override
-  TreeNode visitClass(Class c) {
+  TreeNode visitClass(Class c, TreeNode? removalSentinel) {
     if (_duplicatedMixins.containsKey(c)) {
-      return null; // Class was de-duplicated already, just remove it.
+      // Class was de-duplicated already, just remove it.
+      return removalSentinel!;
     }
 
     if (c.supertype != null) {
-      c.supertype = _transformSupertype(c.supertype, c, true);
+      c.supertype = _transformSupertype(c.supertype!, c, true);
     }
     if (c.mixedInType != null) {
       throw 'All mixins should be transformed already.';
     }
-    transformSupertypeList(c.implementedTypes, this);
+    transformSupertypeList(c.implementedTypes);
 
     if (!c.isAnonymousMixin) {
       return c;
@@ -113,6 +117,7 @@
 
     Class canonical =
         _canonicalMixins.putIfAbsent(new _DeduplicateMixinKey(c), () => c);
+    // ignore: unnecessary_null_comparison
     assert(canonical != null);
 
     if (canonical != c) {
@@ -120,34 +125,34 @@
       // write a dangling reference to the deleted class.
       c.reference.canonicalName = null;
       _duplicatedMixins[c] = canonical;
-      return null; // Remove class.
+      // Remove class.
+      return removalSentinel!;
     }
 
     return c;
   }
 
   @override
-  Supertype visitSupertype(Supertype node) {
+  Supertype visitSupertype(Supertype node, Supertype? removalSentinel) {
     return _transformSupertype(node, null, false);
   }
 
   Supertype _transformSupertype(
-      Supertype supertype, Class cls, bool isSuperclass) {
+      Supertype supertype, Class? cls, bool isSuperclass) {
     Class oldSuper = supertype.classNode;
-    Class newSuper = visitClass(oldSuper);
-    if (newSuper == null) {
-      Class canonicalSuper = _duplicatedMixins[oldSuper];
-      assert(canonicalSuper != null);
+    Class newSuper = visitClass(oldSuper, dummyClass) as Class;
+    if (identical(newSuper, dummyClass)) {
+      Class canonicalSuper = _duplicatedMixins[oldSuper]!;
       supertype = new Supertype(canonicalSuper, supertype.typeArguments);
       if (isSuperclass) {
-        _correctForwardingConstructors(cls, oldSuper, canonicalSuper);
+        _correctForwardingConstructors(cls!, oldSuper, canonicalSuper);
       }
     }
     return supertype;
   }
 
   @override
-  TreeNode defaultTreeNode(TreeNode node) =>
+  TreeNode defaultTreeNode(TreeNode node, TreeNode? removalSentinel) =>
       throw 'Unexpected node ${node.runtimeType}: $node';
 }
 
@@ -204,17 +209,18 @@
 
   @override
   visitSuperMethodInvocation(SuperMethodInvocation node) {
-    node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
+    node.interfaceTarget =
+        _resolveNewInterfaceTarget(node.interfaceTarget) as Procedure?;
     super.visitSuperMethodInvocation(node);
   }
 
-  Member _resolveNewInterfaceTarget(Member m) {
-    final Class c = m?.enclosingClass;
+  Member? _resolveNewInterfaceTarget(Member? m) {
+    final Class? c = m?.enclosingClass;
     if (c != null && c.isAnonymousMixin) {
-      final Class replacement = transformer._duplicatedMixins[c];
+      final Class? replacement = transformer._duplicatedMixins[c];
       if (replacement != null) {
         // The class got removed, so we need to re-resolve the interface target.
-        return _findMember(replacement, m);
+        return _findMember(replacement, m!);
       }
     }
     return m;
@@ -240,8 +246,8 @@
 
   Reference _updateClassReference(Reference classRef) {
     final Class c = classRef.asClass;
-    if (c != null && c.isAnonymousMixin) {
-      final Class replacement = transformer._duplicatedMixins[c];
+    if (c.isAnonymousMixin) {
+      final Class? replacement = transformer._duplicatedMixins[c];
       if (replacement != null) {
         return replacement.reference;
       }
@@ -279,7 +285,7 @@
     for (var initializer in constructor.initializers) {
       if ((initializer is SuperInitializer) &&
           initializer.target.enclosingClass == oldSuper) {
-        Constructor replacement = null;
+        Constructor? replacement = null;
         for (var c in newSuper.constructors) {
           if (c.name == initializer.target.name) {
             replacement = c;
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index ba36509..ac88a41 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -523,8 +523,8 @@
   }
 
   transformComponent(Component component) {
-    _pass1.transform(component);
-    _pass2.transform(component);
+    _pass1.transformComponent(component);
+    _pass2.transformComponent(component);
   }
 
   bool isClassReferencedFromNativeCode(Class c) =>
@@ -563,8 +563,8 @@
       }
       _usedClasses.add(c);
       visitIterable(c.supers, typeVisitor);
-      transformList(c.typeParameters, _pass1, c);
-      transformList(c.annotations, _pass1, c);
+      _pass1.transformTypeParameterList(c.typeParameters, c);
+      _pass1.transformExpressionList(c.annotations, c);
       // Preserve NSM forwarders. They are overlooked by TFA / tree shaker
       // as they are abstract and don't have a body.
       for (Procedure p in c.procedures) {
@@ -615,13 +615,14 @@
       }
 
       if (func != null) {
-        transformList(func.typeParameters, _pass1, func);
-        transformList(func.positionalParameters, _pass1, func);
-        transformList(func.namedParameters, _pass1, func);
+        _pass1.transformTypeParameterList(func.typeParameters, func);
+        _pass1.transformVariableDeclarationList(
+            func.positionalParameters, func);
+        _pass1.transformVariableDeclarationList(func.namedParameters, func);
         func.returnType.accept(typeVisitor);
       }
 
-      transformList(m.annotations, _pass1, m);
+      _pass1.transformExpressionList(m.annotations, m);
 
       // If the member is kept alive we need to keep the extension alive.
       if (m.isExtensionMember) {
@@ -641,18 +642,20 @@
 
   void addUsedExtension(Extension node) {
     if (_usedExtensions.add(node)) {
-      transformList(node.typeParameters, _pass1, node);
+      _pass1.transformTypeParameterList(node.typeParameters, node);
       node.onType?.accept(typeVisitor);
     }
   }
 
   void addUsedTypedef(Typedef typedef) {
     if (_usedTypedefs.add(typedef)) {
-      transformList(typedef.annotations, _pass1, typedef);
-      transformList(typedef.typeParameters, _pass1, typedef);
-      transformList(typedef.typeParametersOfFunctionType, _pass1, typedef);
-      transformList(typedef.positionalParameters, _pass1, typedef);
-      transformList(typedef.namedParameters, _pass1, typedef);
+      _pass1.transformExpressionList(typedef.annotations, typedef);
+      _pass1.transformTypeParameterList(typedef.typeParameters, typedef);
+      _pass1.transformTypeParameterList(
+          typedef.typeParametersOfFunctionType, typedef);
+      _pass1.transformVariableDeclarationList(
+          typedef.positionalParameters, typedef);
+      _pass1.transformVariableDeclarationList(typedef.namedParameters, typedef);
       typedef.type?.accept(typeVisitor);
     }
   }
@@ -786,7 +789,7 @@
 /// Visits all classes, members and bodies of reachable members.
 /// Collects all used classes, members and types, and
 /// transforms unreachable calls into 'throw' expressions.
-class _TreeShakerPass1 extends Transformer {
+class _TreeShakerPass1 extends RemovingTransformer {
   final TreeShaker shaker;
   final FieldMorpher fieldMorpher;
   final TypeEnvironment environment;
@@ -808,8 +811,8 @@
       : fieldMorpher = shaker.fieldMorpher,
         environment = shaker.typeFlowAnalysis.environment;
 
-  void transform(Component component) {
-    component.transformChildren(this);
+  void transformComponent(Component component) {
+    component.transformOrRemoveChildren(this);
   }
 
   bool _isUnreachable(TreeNode node) {
@@ -870,61 +873,62 @@
   NarrowNotNull _getNullTest(TreeNode node) =>
       shaker.typeFlowAnalysis.nullTest(node);
 
-  TreeNode _visitAssertNode(TreeNode node) {
+  TreeNode _visitAssertNode(TreeNode node, TreeNode removalSentinel) {
     if (kRemoveAsserts) {
-      return null;
+      return removalSentinel;
     } else {
-      node.transformChildren(this);
+      node.transformOrRemoveChildren(this);
       return node;
     }
   }
 
   @override
-  DartType visitDartType(DartType node) {
+  DartType visitDartType(DartType node, DartType removalSentinel) {
     node.accept(shaker.typeVisitor);
     return node;
   }
 
   @override
-  Supertype visitSupertype(Supertype node) {
+  Supertype visitSupertype(Supertype node, Supertype removalSentinel) {
     node.accept(shaker.typeVisitor);
     return node;
   }
 
   @override
-  TreeNode visitTypedef(Typedef node) {
+  TreeNode visitTypedef(Typedef node, TreeNode removalSentinel) {
     return node; // Do not go deeper.
   }
 
   @override
-  Extension visitExtension(Extension node) {
+  Extension visitExtension(Extension node, TreeNode removalSentinel) {
     // The extension can be considered a weak node, we'll only retain it if
     // normal code references any of it's members.
     return node;
   }
 
   @override
-  TreeNode visitClass(Class node) {
+  TreeNode visitClass(Class node, TreeNode removalSentinel) {
     if (shaker.isClassAllocated(node) ||
         shaker.isClassReferencedFromNativeCode(node)) {
       shaker.addClassUsedInType(node);
     }
-    transformList(node.constructors, this, node);
-    transformList(node.procedures, this, node);
-    transformList(node.fields, this, node);
-    transformList(node.redirectingFactoryConstructors, this, node);
+    transformConstructorList(node.constructors, node);
+    transformProcedureList(node.procedures, node);
+    transformFieldList(node.fields, node);
+    transformRedirectingFactoryConstructorList(
+        node.redirectingFactoryConstructors, node);
     return node;
   }
 
   @override
-  TreeNode defaultMember(Member node) {
+  TreeNode defaultMember(Member node, TreeNode removalSentinel) {
     currentMember = node;
     if (shaker.isMemberBodyReachable(node)) {
       if (kPrintTrace) {
         tracePrint("Visiting $node");
       }
       shaker.addUsedMember(node);
-      node.transformChildren(this);
+      node.transformOrRemoveChildren(this);
     } else if (shaker.isMemberReferencedFromNativeCode(node)) {
       // Preserve members referenced from native code to satisfy lookups, even
       // if they are not reachable. An instance member could be added via
@@ -937,7 +941,7 @@
   }
 
   @override
-  TreeNode visitField(Field node) {
+  TreeNode visitField(Field node, TreeNode removalSentinel) {
     currentMember = node;
     if (shaker.retainField(node)) {
       if (kPrintTrace) {
@@ -946,7 +950,7 @@
       shaker.addUsedMember(node);
       if (node.initializer != null) {
         if (shaker.isFieldInitializerReachable(node)) {
-          node.transformChildren(this);
+          node.transformOrRemoveChildren(this);
         } else {
           node.initializer = _makeUnreachableCall([])..parent = node;
         }
@@ -961,8 +965,9 @@
   }
 
   @override
-  TreeNode visitMethodInvocation(MethodInvocation node) {
-    node.transformChildren(this);
+  TreeNode visitMethodInvocation(
+      MethodInvocation node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(
           _flattenArguments(node.arguments, receiver: node.receiver));
@@ -984,8 +989,8 @@
   }
 
   @override
-  TreeNode visitPropertyGet(PropertyGet node) {
-    node.transformChildren(this);
+  TreeNode visitPropertyGet(PropertyGet node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.receiver]);
     } else {
@@ -999,8 +1004,8 @@
   }
 
   @override
-  TreeNode visitPropertySet(PropertySet node) {
-    node.transformChildren(this);
+  TreeNode visitPropertySet(PropertySet node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.receiver, node.value]);
     } else {
@@ -1014,8 +1019,9 @@
   }
 
   @override
-  TreeNode visitSuperMethodInvocation(SuperMethodInvocation node) {
-    node.transformChildren(this);
+  TreeNode visitSuperMethodInvocation(
+      SuperMethodInvocation node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(_flattenArguments(node.arguments));
     } else {
@@ -1029,8 +1035,9 @@
   }
 
   @override
-  TreeNode visitSuperPropertyGet(SuperPropertyGet node) {
-    node.transformChildren(this);
+  TreeNode visitSuperPropertyGet(
+      SuperPropertyGet node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([]);
     } else {
@@ -1044,8 +1051,9 @@
   }
 
   @override
-  TreeNode visitSuperPropertySet(SuperPropertySet node) {
-    node.transformChildren(this);
+  TreeNode visitSuperPropertySet(
+      SuperPropertySet node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.value]);
     } else {
@@ -1059,8 +1067,9 @@
   }
 
   @override
-  TreeNode visitStaticInvocation(StaticInvocation node) {
-    node.transformChildren(this);
+  TreeNode visitStaticInvocation(
+      StaticInvocation node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(_flattenArguments(node.arguments));
     }
@@ -1073,8 +1082,8 @@
   }
 
   @override
-  TreeNode visitStaticGet(StaticGet node) {
-    node.transformChildren(this);
+  TreeNode visitStaticGet(StaticGet node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([]);
     } else {
@@ -1088,14 +1097,14 @@
   }
 
   @override
-  Constant visitConstant(Constant node) {
+  Constant visitConstant(Constant node, Constant removalSentinel) {
     shaker.constantVisitor.analyzeConstant(node);
     return node;
   }
 
   @override
-  TreeNode visitStaticSet(StaticSet node) {
-    node.transformChildren(this);
+  TreeNode visitStaticSet(StaticSet node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.value]);
     } else {
@@ -1110,8 +1119,9 @@
   }
 
   @override
-  TreeNode visitConstructorInvocation(ConstructorInvocation node) {
-    node.transformChildren(this);
+  TreeNode visitConstructorInvocation(
+      ConstructorInvocation node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(_flattenArguments(node.arguments));
     } else {
@@ -1125,8 +1135,9 @@
   }
 
   @override
-  TreeNode visitRedirectingInitializer(RedirectingInitializer node) {
-    node.transformChildren(this);
+  TreeNode visitRedirectingInitializer(
+      RedirectingInitializer node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableInitializer(_flattenArguments(node.arguments));
     } else {
@@ -1137,8 +1148,9 @@
   }
 
   @override
-  TreeNode visitSuperInitializer(SuperInitializer node) {
-    node.transformChildren(this);
+  TreeNode visitSuperInitializer(
+      SuperInitializer node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableInitializer(_flattenArguments(node.arguments));
     } else {
@@ -1148,8 +1160,9 @@
   }
 
   @override
-  TreeNode visitFieldInitializer(FieldInitializer node) {
-    node.transformChildren(this);
+  TreeNode visitFieldInitializer(
+      FieldInitializer node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableInitializer([node.value]);
     } else {
@@ -1160,7 +1173,7 @@
           return LocalInitializer(
               VariableDeclaration(null, initializer: node.value));
         } else {
-          return null;
+          return removalSentinel;
         }
       }
       return node;
@@ -1168,23 +1181,25 @@
   }
 
   @override
-  TreeNode visitAssertStatement(AssertStatement node) {
-    return _visitAssertNode(node);
+  TreeNode visitAssertStatement(
+      AssertStatement node, TreeNode removalSentinel) {
+    return _visitAssertNode(node, removalSentinel);
   }
 
   @override
-  TreeNode visitAssertBlock(AssertBlock node) {
-    return _visitAssertNode(node);
+  TreeNode visitAssertBlock(AssertBlock node, TreeNode removalSentinel) {
+    return _visitAssertNode(node, removalSentinel);
   }
 
   @override
-  TreeNode visitAssertInitializer(AssertInitializer node) {
-    return _visitAssertNode(node);
+  TreeNode visitAssertInitializer(
+      AssertInitializer node, TreeNode removalSentinel) {
+    return _visitAssertNode(node, removalSentinel);
   }
 
   @override
-  TreeNode visitAsExpression(AsExpression node) {
-    node.transformChildren(this);
+  TreeNode visitAsExpression(AsExpression node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     TypeCheck check = shaker.typeFlowAnalysis.explicitCast(node);
     if (check != null && check.canAlwaysSkip) {
       return StaticInvocation(
@@ -1195,8 +1210,8 @@
   }
 
   @override
-  TreeNode visitNullCheck(NullCheck node) {
-    node.transformChildren(this);
+  TreeNode visitNullCheck(NullCheck node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     final nullTest = _getNullTest(node);
     if (nullTest.isAlwaysNotNull) {
       return StaticInvocation(
@@ -1221,13 +1236,13 @@
 /// This pass visits classes and members and removes unused classes and members.
 /// Bodies of unreachable but used members are replaced with 'throw'
 /// expressions. This pass does not dive deeper than member level.
-class _TreeShakerPass2 extends Transformer {
+class _TreeShakerPass2 extends RemovingTransformer {
   final TreeShaker shaker;
 
   _TreeShakerPass2(this.shaker);
 
-  void transform(Component component) {
-    component.transformChildren(this);
+  void transformComponent(Component component) {
+    component.transformOrRemoveChildren(this);
     for (Source source in component.uriToSource.values) {
       source?.constantCoverageConstructors?.removeWhere((Reference reference) {
         Member node = reference.asMember;
@@ -1237,8 +1252,8 @@
   }
 
   @override
-  TreeNode visitLibrary(Library node) {
-    node.transformChildren(this);
+  TreeNode visitLibrary(Library node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
     // The transformer API does not iterate over `Library.additionalExports`,
     // so we manually delete the references to shaken nodes.
     node.additionalExports.removeWhere((Reference reference) {
@@ -1257,19 +1272,19 @@
   }
 
   @override
-  Typedef visitTypedef(Typedef node) {
-    return shaker.isTypedefUsed(node) ? node : null;
+  Typedef visitTypedef(Typedef node, TreeNode removalSentinel) {
+    return shaker.isTypedefUsed(node) ? node : removalSentinel;
   }
 
   @override
-  Class visitClass(Class node) {
+  Class visitClass(Class node, TreeNode removalSentinel) {
     if (!shaker.isClassUsed(node)) {
       debugPrint('Dropped class ${node.name}');
       // Ensure that kernel file writer will not be able to
       // write a dangling reference to the deleted class.
       node.reference.canonicalName = null;
       Statistics.classesDropped++;
-      return null; // Remove the class.
+      return removalSentinel; // Remove the class.
     }
 
     if (!shaker.isClassUsedInType(node)) {
@@ -1292,7 +1307,7 @@
       node.isAbstract = true;
     }
 
-    node.transformChildren(this);
+    node.transformOrRemoveChildren(this);
 
     return node;
   }
@@ -1305,13 +1320,13 @@
       node.enclosingClass.isEnum;
 
   @override
-  Member defaultMember(Member node) {
+  Member defaultMember(Member node, TreeNode removalSentinel) {
     if (!shaker.isMemberUsed(node) && !_preserveSpecialMember(node)) {
       // Ensure that kernel file writer will not be able to
       // write a dangling reference to the deleted member.
       node.reference.canonicalName = null;
       Statistics.membersDropped++;
-      return null;
+      return removalSentinel;
     }
 
     if (!shaker.isMemberBodyReachable(node)) {
@@ -1358,7 +1373,7 @@
   }
 
   @override
-  Extension visitExtension(Extension node) {
+  Extension visitExtension(Extension node, TreeNode removalSentinel) {
     if (shaker.isExtensionUsed(node)) {
       int writeIndex = 0;
       for (int i = 0; i < node.members.length; ++i) {
@@ -1379,7 +1394,7 @@
       assert(node.members.length > 0);
       return node;
     }
-    return null;
+    return removalSentinel;
   }
 
   void _makeUnreachableBody(FunctionNode function) {
@@ -1391,7 +1406,7 @@
   }
 
   @override
-  TreeNode defaultTreeNode(TreeNode node) {
+  TreeNode defaultTreeNode(TreeNode node, TreeNode removalSentinel) {
     return node; // Do not traverse into other nodes.
   }
 }
diff --git a/pkg/vm/lib/transformations/unreachable_code_elimination.dart b/pkg/vm/lib/transformations/unreachable_code_elimination.dart
index 8444ce7..10bd958 100644
--- a/pkg/vm/lib/transformations/unreachable_code_elimination.dart
+++ b/pkg/vm/lib/transformations/unreachable_code_elimination.dart
@@ -2,17 +2,20 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.12
+
 import 'package:kernel/ast.dart';
 
 /// Simple unreachable code elimination: removes asserts and if statements
 /// with constant conditions. Does a very limited constant folding of
 /// logical expressions.
 Component transformComponent(Component component, bool enableAsserts) {
-  new SimpleUnreachableCodeElimination(enableAsserts).visitComponent(component);
+  new SimpleUnreachableCodeElimination(enableAsserts)
+      .visitComponent(component, null);
   return component;
 }
 
-class SimpleUnreachableCodeElimination extends Transformer {
+class SimpleUnreachableCodeElimination extends RemovingTransformer {
   final bool enableAsserts;
 
   SimpleUnreachableCodeElimination(this.enableAsserts);
@@ -37,24 +40,27 @@
   Expression _createBoolLiteral(bool value, int fileOffset) =>
       new BoolLiteral(value)..fileOffset = fileOffset;
 
-  Statement _makeEmptyBlockIfNull(Statement node, TreeNode parent) =>
-      node == null ? (Block(<Statement>[])..parent = parent) : node;
+  Statement _makeEmptyBlockIfEmptyStatement(Statement node, TreeNode parent) =>
+      node is EmptyStatement ? (Block(<Statement>[])..parent = parent) : node;
 
   @override
-  TreeNode visitIfStatement(IfStatement node) {
-    node.transformChildren(this);
+  TreeNode visitIfStatement(IfStatement node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
     final condition = node.condition;
     if (_isBoolConstant(condition)) {
       final value = _getBoolConstantValue(condition);
-      return value ? node.then : node.otherwise;
+      return value
+          ? node.then
+          : (node.otherwise ?? removalSentinel ?? new EmptyStatement());
     }
-    node.then = _makeEmptyBlockIfNull(node.then, node);
+    node.then = _makeEmptyBlockIfEmptyStatement(node.then, node);
     return node;
   }
 
   @override
-  visitConditionalExpression(ConditionalExpression node) {
-    node.transformChildren(this);
+  visitConditionalExpression(
+      ConditionalExpression node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
     final condition = node.condition;
     if (_isBoolConstant(condition)) {
       final value = _getBoolConstantValue(condition);
@@ -64,8 +70,8 @@
   }
 
   @override
-  TreeNode visitNot(Not node) {
-    node.transformChildren(this);
+  TreeNode visitNot(Not node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
     final operand = node.operand;
     if (_isBoolConstant(operand)) {
       return _createBoolLiteral(
@@ -75,8 +81,9 @@
   }
 
   @override
-  TreeNode visitLogicalExpression(LogicalExpression node) {
-    node.transformChildren(this);
+  TreeNode visitLogicalExpression(
+      LogicalExpression node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
     final left = node.left;
     final right = node.right;
     final operatorEnum = node.operatorEnum;
@@ -104,8 +111,8 @@
   }
 
   @override
-  visitStaticGet(StaticGet node) {
-    node.transformChildren(this);
+  visitStaticGet(StaticGet node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
     final target = node.target;
     if (target is Field && target.isConst) {
       throw 'StaticGet from const field $target should be evaluated by front-end: $node';
@@ -114,34 +121,38 @@
   }
 
   @override
-  TreeNode visitAssertStatement(AssertStatement node) {
+  TreeNode visitAssertStatement(
+      AssertStatement node, TreeNode? removalSentinel) {
     if (!enableAsserts) {
-      return null;
+      return removalSentinel ?? new EmptyStatement();
     }
-    return super.visitAssertStatement(node);
+    return super.visitAssertStatement(node, removalSentinel);
   }
 
   @override
-  TreeNode visitAssertBlock(AssertBlock node) {
+  TreeNode visitAssertBlock(AssertBlock node, TreeNode? removalSentinel) {
     if (!enableAsserts) {
-      return null;
+      return removalSentinel ?? new EmptyStatement();
     }
-    return super.visitAssertBlock(node);
+    return super.visitAssertBlock(node, removalSentinel);
   }
 
   @override
-  TreeNode visitAssertInitializer(AssertInitializer node) {
+  TreeNode visitAssertInitializer(
+      AssertInitializer node, TreeNode? removalSentinel) {
     if (!enableAsserts) {
-      return null;
+      // Initializers only occur in the initializer list where they are always
+      // removable.
+      return removalSentinel!;
     }
-    return super.visitAssertInitializer(node);
+    return super.visitAssertInitializer(node, removalSentinel);
   }
 
   @override
-  TreeNode visitTryFinally(TryFinally node) {
-    node.transformChildren(this);
+  TreeNode visitTryFinally(TryFinally node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
     final fin = node.finalizer;
-    if (fin == null || (fin is Block && fin.statements.isEmpty)) {
+    if (fin is EmptyStatement || (fin is Block && fin.statements.isEmpty)) {
       return node.body;
     }
     return node;
@@ -157,8 +168,8 @@
   }
 
   @override
-  TreeNode visitTryCatch(TryCatch node) {
-    node.transformChildren(this);
+  TreeNode visitTryCatch(TryCatch node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
     // Can replace try/catch with its body if all catches are just rethow.
     for (Catch catchClause in node.catches) {
       if (!_isRethrow(catchClause.body)) {
@@ -174,30 +185,30 @@
   // need to guard against null.
 
   @override
-  TreeNode visitWhileStatement(WhileStatement node) {
-    node.transformChildren(this);
-    node.body = _makeEmptyBlockIfNull(node.body, node);
+  TreeNode visitWhileStatement(WhileStatement node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    node.body = _makeEmptyBlockIfEmptyStatement(node.body, node);
     return node;
   }
 
   @override
-  TreeNode visitDoStatement(DoStatement node) {
-    node.transformChildren(this);
-    node.body = _makeEmptyBlockIfNull(node.body, node);
+  TreeNode visitDoStatement(DoStatement node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    node.body = _makeEmptyBlockIfEmptyStatement(node.body, node);
     return node;
   }
 
   @override
-  TreeNode visitForStatement(ForStatement node) {
-    node.transformChildren(this);
-    node.body = _makeEmptyBlockIfNull(node.body, node);
+  TreeNode visitForStatement(ForStatement node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    node.body = _makeEmptyBlockIfEmptyStatement(node.body, node);
     return node;
   }
 
   @override
-  TreeNode visitForInStatement(ForInStatement node) {
-    node.transformChildren(this);
-    node.body = _makeEmptyBlockIfNull(node.body, node);
+  TreeNode visitForInStatement(ForInStatement node, TreeNode? removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    node.body = _makeEmptyBlockIfEmptyStatement(node.body, node);
     return node;
   }
 }
diff --git a/tools/VERSION b/tools/VERSION
index ad78b64..f0413ea 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 50
+PRERELEASE 51
 PRERELEASE_PATCH 0
\ No newline at end of file