Migrate pkg/vm to null safety, part 3

TEST=ci

Issue: https://github.com/dart-lang/sdk/issues/46620
Change-Id: I1ab793eec6ffd7e01cee1e6641138e96a4f4d9fc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/207864
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 83c9a50..75eff47 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -2,10 +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 file.
 
-// @dart=2.9
-
 /// Global type flow analysis.
-library kernel.transformations.analysis;
 
 import 'dart:collection';
 import 'dart:core' hide Type;
@@ -51,24 +48,28 @@
 
 /// Maintains set of dependent invocations.
 class _DependencyTracker {
-  Set<_Invocation> _dependentInvocations;
+  Set<_Invocation>? _dependentInvocations;
 
   void addDependentInvocation(_Invocation invocation) {
     if (!identical(invocation, this)) {
-      _dependentInvocations ??= new Set<_Invocation>();
-      _dependentInvocations.add(invocation);
+      var dependentInvocations = _dependentInvocations;
+      if (dependentInvocations == null) {
+        _dependentInvocations = dependentInvocations = Set<_Invocation>();
+      }
+      dependentInvocations.add(invocation);
     }
   }
 
   void invalidateDependentInvocations(_WorkList workList) {
-    if (_dependentInvocations != null) {
+    final dependentInvocations = _dependentInvocations;
+    if (dependentInvocations != null) {
       if (kPrintTrace) {
         tracePrint('   - CHANGED: $this');
-        for (var di in _dependentInvocations) {
+        for (var di in dependentInvocations) {
           tracePrint('     - invalidating $di');
         }
       }
-      _dependentInvocations.forEach(workList.invalidateInvocation);
+      dependentInvocations.forEach(workList.invalidateInvocation);
     }
   }
 }
@@ -83,12 +84,12 @@
   final Selector selector;
   final Args<Type> args;
 
-  Type result;
+  Type? result;
 
   /// Result of the invocation calculated before invocation was invalidated.
   /// Used to check if the re-analysis of the invocation yields the same
   /// result or not (to avoid invalidation of callers if result hasn't changed).
-  Type invalidatedResult;
+  Type? invalidatedResult;
 
   /// Number of times result of this invocation was invalidated.
   int invalidationCounter = 0;
@@ -108,7 +109,7 @@
   /// Returns result of this invocation if its available without
   /// further analysis, or `null` if it's not available.
   /// Used for recursive calls while this invocation is being processed.
-  Type get resultForRecursiveInvocation => result;
+  Type? get resultForRecursiveInvocation => result;
 
   /// Use [type] as a current computed result of this invocation.
   /// If this invocation was invalidated, and the invalidated result is
@@ -116,7 +117,6 @@
   /// Result type may be saturated if this invocation was invalidated
   /// too many times.
   void setResult(TypeFlowAnalysis typeFlowAnalysis, Type type) {
-    assert(type != null);
     result = type;
 
     if (invalidatedResult != null) {
@@ -132,8 +132,8 @@
         // the analysis, result is saturated after invocation is invalidated
         // at least [_Invocation.invalidationLimit] times.
         if (invalidationCounter > _Invocation.invalidationLimit) {
-          result =
-              result.union(invalidatedResult, typeFlowAnalysis.hierarchyCache);
+          result = result!
+              .union(invalidatedResult!, typeFlowAnalysis.hierarchyCache);
         }
       }
       invalidatedResult = null;
@@ -192,11 +192,12 @@
     // they could fail bounds checks.
     //
     // TODO(sjindel): Use [TypeCheck] to avoid bounds checks.
-    if (selector.member.function != null) {
-      typeChecksNeeded = selector.member.function.typeParameters
-          .any((t) => t.isGenericCovariantImpl);
+    final function = selector.member.function;
+    if (function != null) {
+      typeChecksNeeded =
+          function.typeParameters.any((t) => t.isGenericCovariantImpl);
     } else {
-      Field field = selector.member;
+      Field field = selector.member as Field;
       if (selector.callKind == CallKind.PropertySet) {
         // TODO(dartbug.com/40615): Use TFA results to improve this criterion.
         typeChecksNeeded = field.isGenericCovariantImpl;
@@ -277,13 +278,10 @@
         fieldValue.isInitialized = true;
         return const EmptyType();
     }
-
-    // Make dartanalyzer happy.
-    throw 'Unexpected call kind ${selector.callKind}';
   }
 
   Type _processFunction(TypeFlowAnalysis typeFlowAnalysis) {
-    final Member member = selector.member;
+    final Member member = selector.member!;
     if (selector.memberAgreesToCallKind(member)) {
       if (_argumentsValid()) {
         final summary = typeFlowAnalysis.getSummary(member);
@@ -326,13 +324,12 @@
   }
 
   bool _argumentsValid() {
-    final function = selector.member.function;
-    assert(function != null);
-
+    final member = selector.member!;
+    final function = member.function!;
     final int positionalArguments = args.positionalCount;
 
-    final int firstParamIndex = numTypeParams(selector.member) +
-        (hasReceiverArg(selector.member) ? 1 : 0);
+    final int firstParamIndex =
+        numTypeParams(member) + (hasReceiverArg(member) ? 1 : 0);
     final int requiredParameters =
         firstParamIndex + function.requiredParameterCount;
     if (positionalArguments < requiredParameters) {
@@ -361,9 +358,9 @@
 
 class _DispatchableInvocation extends _Invocation {
   bool _isPolymorphic = false;
-  Set<Call> _callSites; // Populated only if not polymorphic.
-  Member _monomorphicTarget;
-  _DirectInvocation _monomorphicDirectInvocation;
+  Set<Call>? _callSites; // Populated only if not polymorphic.
+  Member? _monomorphicTarget;
+  _DirectInvocation? _monomorphicDirectInvocation;
 
   @override
   set typeChecksNeeded(bool value) {
@@ -434,7 +431,8 @@
 
           if (!_isPolymorphic) {
             assert(target == _monomorphicTarget);
-            _monomorphicDirectInvocation = directInvocation;
+            _monomorphicDirectInvocation =
+                directInvocation as _DirectInvocation;
           }
 
           type = typeFlowAnalysis.workList.processInvocation(directInvocation);
@@ -486,13 +484,13 @@
 
     final bool isNullableReceiver = receiver is NullableType;
     if (isNullableReceiver) {
-      receiver = (receiver as NullableType).baseType;
+      receiver = receiver.baseType;
       assert(receiver is! NullableType);
     }
 
     if (selector is InterfaceSelector) {
       final staticReceiverType = new ConeType(typeFlowAnalysis.hierarchyCache
-          .getTFClass(selector.member.enclosingClass));
+          .getTFClass(selector.member!.enclosingClass!));
       receiver = receiver.intersection(
           staticReceiverType, typeFlowAnalysis.hierarchyCache);
       assert(receiver is! NullableType);
@@ -507,7 +505,7 @@
       // invocation to the receiver class. A new allocated class discovered
       // in the receiver cone will invalidate this invocation.
       receiver = typeFlowAnalysis.hierarchyCache
-          .specializeTypeCone((receiver as ConeType).cls, allowWideCone: false);
+          .specializeTypeCone(receiver.cls, allowWideCone: false);
     }
 
     assert(targets.isEmpty);
@@ -535,7 +533,7 @@
     Class nullClass =
         typeFlowAnalysis.environment.coreTypes.deprecatedNullClass;
 
-    Member target = typeFlowAnalysis.hierarchyCache.hierarchy
+    Member? target = typeFlowAnalysis.hierarchyCache.hierarchy
         .getDispatchTarget(nullClass, selector.name, setter: selector.isSetter);
 
     if (target != null) {
@@ -552,7 +550,7 @@
       TypeFlowAnalysis typeFlowAnalysis) {
     final TFClass cls = receiver.cls;
 
-    Member target =
+    Member? target =
         (cls as _TFClassImpl).getDispatchTarget(selector, typeFlowAnalysis);
 
     if (target != null) {
@@ -647,8 +645,9 @@
     if (_isPolymorphic) {
       callSite.setPolymorphic();
     } else {
-      if (_monomorphicTarget != null) {
-        callSite.addTarget(_monomorphicTarget);
+      final monomorphicTarget = _monomorphicTarget;
+      if (monomorphicTarget != null) {
+        callSite.addTarget(monomorphicTarget);
       }
     }
 
@@ -660,18 +659,20 @@
   /// Notify call sites monitoring this invocation about changes in
   /// polymorphism of this invocation.
   void _notifyCallSites() {
-    if (_callSites != null) {
-      _callSites.forEach(_notifyCallSite);
+    final callSites = _callSites;
+    if (callSites != null) {
+      callSites.forEach(_notifyCallSite);
     }
   }
 
   @override
-  Type get resultForRecursiveInvocation {
+  Type? get resultForRecursiveInvocation {
     if (result != null) {
       return result;
     }
-    if (_monomorphicDirectInvocation != null) {
-      return _monomorphicDirectInvocation.resultForRecursiveInvocation;
+    final monomorphicDirectInvocation = _monomorphicDirectInvocation;
+    if (monomorphicDirectInvocation != null) {
+      return monomorphicDirectInvocation.resultForRecursiveInvocation;
     }
     return null;
   }
@@ -683,30 +684,30 @@
 /// 1) Add 1..N concrete types ordered by classId OR add 1 arbitrary type.
 /// 2) Make type nullable.
 class _ReceiverTypeBuilder {
-  Type _type;
-  List<ConcreteType> _list;
+  Type? _type;
+  List<ConcreteType>? _list;
   bool _nullable = false;
 
   /// Appends a ConcreteType. May be called multiple times.
   /// Should not be used in conjunction with [addType].
   void addConcreteType(ConcreteType type) {
-    if (_list == null) {
-      if (_type == null) {
+    final list = _list;
+    if (list == null) {
+      final Type? t = _type;
+      if (t == null) {
         _type = type;
         return;
       }
+      final ct = t as ConcreteType;
 
-      assert(_type is ConcreteType);
-      assert(_type != type);
-
-      _list = <ConcreteType>[];
-      _list.add(_type);
-
+      assert(ct != type);
+      assert(ct.cls.id < type.cls.id);
+      _list = <ConcreteType>[ct, type];
       _type = null;
+    } else {
+      assert(list.last.cls.id < type.cls.id);
+      list.add(type);
     }
-
-    assert(_list.last.cls.id < type.cls.id);
-    _list.add(type);
   }
 
   /// Appends an arbitrary Type. May be called only once.
@@ -723,12 +724,13 @@
 
   /// Returns union of added types.
   Type toType() {
-    Type t = _type;
+    Type? t = _type;
     if (t == null) {
-      if (_list == null) {
+      final list = _list;
+      if (list == null) {
         t = const EmptyType();
       } else {
-        t = new SetType(_list);
+        t = SetType(list);
       }
     } else {
       assert(_list == null);
@@ -753,7 +755,7 @@
   static const int maxInvocationsPerSelector = 5000;
 
   int count = 0;
-  _Invocation approximation;
+  _Invocation? approximation;
 }
 
 /// Maintains ([Selector], [Args]) => [_Invocation] cache.
@@ -771,7 +773,7 @@
     _Invocation invocation = (selector is DirectSelector)
         ? new _DirectInvocation(selector, args)
         : new _DispatchableInvocation(selector, args);
-    _Invocation result = _invocations.lookup(invocation);
+    _Invocation? result = _invocations.lookup(invocation);
     if (result != null) {
       return result;
     }
@@ -784,14 +786,16 @@
       final sa = (_approximations[selector] ??= new _SelectorApproximation());
 
       if (sa.count >= _SelectorApproximation.maxInvocationsPerSelector) {
-        if (sa.approximation == null) {
+        _Invocation? approximation = sa.approximation;
+        if (approximation == null) {
           final rawArgs =
               _typeFlowAnalysis.summaryCollector.rawArguments(selector);
-          sa.approximation = new _DispatchableInvocation(selector, rawArgs);
+          sa.approximation =
+              approximation = _DispatchableInvocation(selector, rawArgs);
           Statistics.approximateInvocationsCreated++;
         }
         Statistics.approximateInvocationsUsed++;
-        return sa.approximation;
+        return approximation;
       }
 
       ++sa.count;
@@ -809,8 +813,8 @@
 class _FieldValue extends _DependencyTracker {
   final Field field;
   final Type staticType;
-  final Summary typeGuardSummary;
-  Type value;
+  final Summary? typeGuardSummary;
+  Type value = const EmptyType();
 
   /// Flag indicating if field initializer was executed.
   bool isInitialized = false;
@@ -825,8 +829,6 @@
       : staticType = typesBuilder.fromStaticType(field.type, true) {
     if (field.initializer == null && _isDefaultValueOfFieldObservable()) {
       value = new Type.nullable(const EmptyType());
-    } else {
-      value = const EmptyType();
     }
   }
 
@@ -839,8 +841,7 @@
       return true;
     }
 
-    final enclosingClass = field.enclosingClass;
-    assert(enclosingClass != null);
+    final enclosingClass = field.enclosingClass!;
 
     // Default value is not observable if every generative constructor
     // is redirecting or initializes the field.
@@ -856,10 +857,11 @@
     });
   }
 
-  void ensureInitialized(TypeFlowAnalysis typeFlowAnalysis, Type receiverType) {
+  void ensureInitialized(
+      TypeFlowAnalysis typeFlowAnalysis, Type? receiverType) {
     if (field.initializer != null) {
       assert(field.isStatic == (receiverType == null));
-      final args = !field.isStatic ? <Type>[receiverType] : const <Type>[];
+      final args = !field.isStatic ? <Type>[receiverType!] : const <Type>[];
       final initializerInvocation = typeFlowAnalysis._invocationsCache
           .getInvocation(
               new DirectSelector(field, callKind: CallKind.FieldInitializer),
@@ -870,17 +872,18 @@
     }
   }
 
-  Type getValue(TypeFlowAnalysis typeFlowAnalysis, Type receiverType) {
+  Type getValue(TypeFlowAnalysis typeFlowAnalysis, Type? receiverType) {
     ensureInitialized(typeFlowAnalysis, receiverType);
     addDependentInvocation(typeFlowAnalysis.currentInvocation);
+    final typeGuardSummary = this.typeGuardSummary;
     return (typeGuardSummary != null)
-        ? typeGuardSummary.apply(Args([receiverType, value]),
+        ? typeGuardSummary.apply(Args([receiverType!, value]),
             typeFlowAnalysis.hierarchyCache, typeFlowAnalysis)
         : value;
   }
 
   void setValue(
-      Type newValue, TypeFlowAnalysis typeFlowAnalysis, Type receiverType) {
+      Type newValue, TypeFlowAnalysis typeFlowAnalysis, Type? receiverType) {
     // Make sure type cones are specialized before putting them into field
     // value, in order to ensure that dependency is established between
     // cone's base type and corresponding field setter.
@@ -907,10 +910,11 @@
     //
     final hierarchy = typeFlowAnalysis.hierarchyCache;
     // TODO(sjindel/tfa): Perform narrowing inside 'TypeCheck'.
+    final typeGuardSummary = this.typeGuardSummary;
     final narrowedNewValue = typeGuardSummary != null
         ? typeGuardSummary
-            .apply(
-                new Args([receiverType, newValue]), hierarchy, typeFlowAnalysis)
+            .apply(new Args([receiverType!, newValue]), hierarchy,
+                typeFlowAnalysis)
             .intersection(staticType, hierarchy)
         : newValue.specialize(hierarchy).intersection(staticType, hierarchy);
     Type newType =
@@ -952,28 +956,26 @@
   /// Flag indicating if this class has a noSuchMethod() method not inherited
   /// from Object.
   /// Lazy initialized by ClassHierarchyCache.hasNonTrivialNoSuchMethod().
-  bool hasNonTrivialNoSuchMethod;
+  bool? hasNonTrivialNoSuchMethod;
 
   _TFClassImpl(int id, Class classNode, this.supertypes)
       : super(id, classNode) {
     supertypes.add(this);
   }
 
-  ConcreteType _concreteType;
-  ConcreteType get concreteType =>
-      _concreteType ??= new ConcreteType(this, null);
+  late final ConcreteType concreteType = ConcreteType(this, null);
 
-  Type _specializedConeType;
+  Type? _specializedConeType;
   Type get specializedConeType =>
       _specializedConeType ??= _calculateConeTypeSpecialization();
 
   bool get hasWideCone =>
       _allocatedSubtypes.length > maxAllocatedTypesInSetSpecializations;
 
-  WideConeType _wideConeType;
+  late final WideConeType _wideConeType = WideConeType(this);
   WideConeType get wideConeType {
     assert(hasWideCone);
-    return _wideConeType ??= new WideConeType(this);
+    return _wideConeType;
   }
 
   Type _calculateConeTypeSpecialization() {
@@ -999,14 +1001,16 @@
     _specializedConeType = null; // Reset cached specialization.
   }
 
-  Member getDispatchTarget(
+  Member? getDispatchTarget(
       Selector selector, TypeFlowAnalysis typeFlowAnalysis) {
-    Member target = _dispatchTargets[selector];
+    Member? target = _dispatchTargets[selector];
     if (target == null) {
       target = typeFlowAnalysis.hierarchyCache.hierarchy.getDispatchTarget(
           classNode, selector.name,
           setter: selector.isSetter);
-      _dispatchTargets[selector] = target;
+      if (target != null) {
+        _dispatchTargets[selector] = target;
+      }
     }
     return target;
   }
@@ -1021,10 +1025,11 @@
   final cachedFlattenedTypeArgs = <Class, List<DartType>>{};
   final cachedFlattenedTypeArgsForNonGeneric = <Class, List<Type>>{};
 
-  RuntimeTypeTranslatorImpl closedTypeTranslator;
+  late final RuntimeTypeTranslatorImpl closedTypeTranslator;
 
-  GenericInterfacesInfoImpl(this.hierarchy) {
-    closedTypeTranslator = RuntimeTypeTranslatorImpl.forClosedTypes(this);
+  GenericInterfacesInfoImpl(CoreTypes coreTypes, this.hierarchy) {
+    closedTypeTranslator =
+        RuntimeTypeTranslatorImpl.forClosedTypes(coreTypes, this);
   }
 
   List<DartType> flattenedTypeArgumentsFor(Class klass, {bool useCache: true}) {
@@ -1049,7 +1054,7 @@
     if (klass == iface) return 0;
 
     final pair = new SubtypePair(klass, iface);
-    int offset = supertypeOffsetsCache[pair];
+    int? offset = supertypeOffsetsCache[pair];
 
     if (offset != null) return offset;
 
@@ -1064,16 +1069,16 @@
   }
 
   List<Type> flattenedTypeArgumentsForNonGeneric(Class klass) {
-    List<Type> result = cachedFlattenedTypeArgsForNonGeneric[klass];
+    List<Type>? result = cachedFlattenedTypeArgsForNonGeneric[klass];
     if (result != null) return result;
 
     List<DartType> flattenedTypeArgs =
         flattenedTypeArgumentsFor(klass, useCache: false);
-    result = new List<Type>.filled(flattenedTypeArgs.length, null);
-    for (int i = 0; i < flattenedTypeArgs.length; ++i) {
-      final translated = closedTypeTranslator.translate(flattenedTypeArgs[i]);
+    result = <Type>[];
+    for (DartType arg in flattenedTypeArgs) {
+      final translated = closedTypeTranslator.translate(arg);
       assert(translated is RuntimeType || translated is UnknownType);
-      result[i] = translated;
+      result.add(translated as Type);
     }
     cachedFlattenedTypeArgsForNonGeneric[klass] = result;
     return result;
@@ -1108,10 +1113,8 @@
   _ClassHierarchyCache(this._typeFlowAnalysis, this.hierarchy,
       this.genericInterfacesInfo, this.environment, bool nullSafety)
       : objectNoSuchMethod = hierarchy.getDispatchTarget(
-            environment.coreTypes.objectClass, noSuchMethodName),
-        super(environment.coreTypes, nullSafety) {
-    assert(objectNoSuchMethod != null);
-  }
+            environment.coreTypes.objectClass, noSuchMethodName)!,
+        super(environment.coreTypes, nullSafety);
 
   @override
   _TFClassImpl getTFClass(Class c) {
@@ -1198,10 +1201,13 @@
 
   bool hasNonTrivialNoSuchMethod(TFClass c) {
     final classImpl = c as _TFClassImpl;
-    classImpl.hasNonTrivialNoSuchMethod ??=
-        (hierarchy.getDispatchTarget(c.classNode, noSuchMethodName) !=
-            objectNoSuchMethod);
-    return classImpl.hasNonTrivialNoSuchMethod;
+    bool? value = classImpl.hasNonTrivialNoSuchMethod;
+    if (value == null) {
+      classImpl.hasNonTrivialNoSuchMethod = value =
+          (hierarchy.getDispatchTarget(c.classNode, noSuchMethodName) !=
+              objectNoSuchMethod);
+    }
+    return value;
   }
 
   _DynamicTargetSet getDynamicTargetSet(DynamicSelector selector) {
@@ -1294,10 +1300,11 @@
   }
 
   bool invalidateProtobufFields() {
-    if (_typeFlowAnalysis.protobufHandler == null) {
+    final protobufHandler = _typeFlowAnalysis.protobufHandler;
+    if (protobufHandler == null) {
       return false;
     }
-    final fields = _typeFlowAnalysis.protobufHandler.getInvalidatedFields();
+    final fields = protobufHandler.getInvalidatedFields();
     if (fields.isEmpty) {
       return false;
     }
@@ -1305,7 +1312,7 @@
     for (var field in fields) {
       assert(field.isStatic);
       // Reset summary in order to rebuild it.
-      _typeFlowAnalysis._summaries[field] = null;
+      _typeFlowAnalysis._summaries.remove(field);
       // Invalidate (and enqueue) field initializer invocation.
       final initializerInvocation = _typeFlowAnalysis._invocationsCache
           .getInvocation(
@@ -1328,10 +1335,11 @@
   }
 
   Type processInvocation(_Invocation invocation) {
-    if (invocation.result != null) {
+    Type? result = invocation.result;
+    if (result != null) {
       // Already processed.
       Statistics.usedCachedResultsOfInvocations++;
-      return invocation.result;
+      return result;
     }
 
     // Test if tracing is enabled to avoid expensive message formatting.
@@ -1374,18 +1382,18 @@
               -1);
         }
         processing.remove(invocation);
-        return invocation.invalidatedResult;
+        return invocation.invalidatedResult!;
       }
 
       callStack.add(invocation);
       pending.remove(invocation);
 
-      Type result = invocation.process(_typeFlowAnalysis);
+      result = invocation.process(_typeFlowAnalysis);
 
       invocation.setResult(_typeFlowAnalysis, result);
 
       // setResult may saturate result to ensure convergence.
-      result = invocation.result;
+      result = invocation.result!;
 
       // Invocation is still pending - it was invalidated while being processed.
       // Move result to invalidatedResult.
@@ -1434,12 +1442,12 @@
   final TypeEnvironment environment;
   final LibraryIndex libraryIndex;
   final PragmaAnnotationParser annotationMatcher;
-  final ProtobufHandler protobufHandler;
-  NativeCodeOracle nativeCodeOracle;
-  _ClassHierarchyCache hierarchyCache;
-  SummaryCollector summaryCollector;
-  _InvocationsCache _invocationsCache;
-  _WorkList workList;
+  final ProtobufHandler? protobufHandler;
+  late NativeCodeOracle nativeCodeOracle;
+  late _ClassHierarchyCache hierarchyCache;
+  late SummaryCollector summaryCollector;
+  late _InvocationsCache _invocationsCache;
+  late _WorkList workList;
   GenericInterfacesInfo _genericInterfacesInfo;
 
   final Map<Member, Summary> _summaries = <Member, Summary>{};
@@ -1459,7 +1467,7 @@
       this.environment,
       this.libraryIndex,
       this.protobufHandler,
-      PragmaAnnotationParser matcher)
+      PragmaAnnotationParser? matcher)
       : annotationMatcher =
             matcher ?? new ConstantPragmaAnnotationParser(coreTypes) {
     nativeCodeOracle = new NativeCodeOracle(libraryIndex, annotationMatcher);
@@ -1488,9 +1496,9 @@
   }
 
   _FieldValue getFieldValue(Field field) {
-    _FieldValue fieldValue = _fieldValues[field];
+    _FieldValue? fieldValue = _fieldValues[field];
     if (fieldValue == null) {
-      Summary typeGuardSummary = null;
+      Summary? typeGuardSummary = null;
       if (field.isGenericCovariantImpl) {
         typeGuardSummary = summaryCollector.createSummary(field,
             fieldSummaryType: FieldSummaryType.kFieldGuard);
@@ -1548,24 +1556,24 @@
 
   bool isClassAllocated(Class c) => hierarchyCache.allocatedClasses.contains(c);
 
-  Call callSite(TreeNode node) => summaryCollector.callSites[node];
+  Call? callSite(TreeNode node) => summaryCollector.callSites[node];
 
-  TypeCheck explicitCast(AsExpression cast) =>
+  TypeCheck? explicitCast(AsExpression cast) =>
       summaryCollector.explicitCasts[cast];
 
-  TypeCheck isTest(IsExpression node) => summaryCollector.isTests[node];
+  TypeCheck? isTest(IsExpression node) => summaryCollector.isTests[node];
 
-  NarrowNotNull nullTest(TreeNode node) => summaryCollector.nullTests[node];
+  NarrowNotNull? nullTest(TreeNode node) => summaryCollector.nullTests[node];
 
-  Type fieldType(Field field) => _fieldValues[field]?.value;
+  Type? fieldType(Field field) => _fieldValues[field]?.value;
 
-  Args<Type> argumentTypes(Member member) => _summaries[member]?.argumentTypes;
+  Args<Type>? argumentTypes(Member member) => _summaries[member]?.argumentTypes;
 
-  Type argumentType(Member member, VariableDeclaration memberParam) {
+  Type? argumentType(Member member, VariableDeclaration memberParam) {
     return _summaries[member]?.argumentType(member, memberParam);
   }
 
-  List<VariableDeclaration> uncheckedParameters(Member member) =>
+  List<VariableDeclaration>? uncheckedParameters(Member member) =>
       _summaries[member]?.uncheckedParameters;
 
   bool isTearOffTaken(Member member) => _tearOffTaken.contains(member);
@@ -1599,7 +1607,7 @@
   /// ---- Implementation of [CallHandler] interface. ----
 
   @override
-  Type applyCall(Call callSite, Selector selector, Args<Type> args,
+  Type applyCall(Call? callSite, Selector selector, Args<Type> args,
       {bool isResultUsed: true, bool processImmediately: true}) {
     _Invocation invocation = _invocationsCache.getInvocation(selector, args);
 
@@ -1629,7 +1637,7 @@
         workList.enqueueInvocation(invocation);
       }
 
-      return null;
+      return const EmptyType();
     }
   }
 
@@ -1680,7 +1688,7 @@
   }
 
   @override
-  void recordTearOff(Procedure target) {
+  void recordTearOff(Member target) {
     _tearOffTaken.add(target);
   }
 }
diff --git a/pkg/vm/lib/transformations/type_flow/calls.dart b/pkg/vm/lib/transformations/type_flow/calls.dart
index 060500a..dd16279d 100644
--- a/pkg/vm/lib/transformations/type_flow/calls.dart
+++ b/pkg/vm/lib/transformations/type_flow/calls.dart
@@ -2,10 +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 file.
 
-// @dart=2.9
-
 /// Declares classes which describe a call: selectors and arguments.
-library vm.transformations.type_flow.calls;
 
 import 'dart:core' hide Type;
 
@@ -30,10 +27,10 @@
   Selector(this.callKind);
 
   /// Interface or concrete target, may be null.
-  Member get member;
+  Member? get member;
 
   /// Selector name.
-  Name get name => member.name;
+  Name get name => member!.name;
 
   bool get isSetter => (callKind == CallKind.PropertySet);
 
@@ -46,6 +43,7 @@
 
   /// Static approximation of Dart return type.
   DartType get staticReturnType {
+    final member = this.member;
     if (member == null) {
       return const DynamicType();
     }
@@ -61,7 +59,6 @@
       case CallKind.SetFieldInConstructor:
         return const NeverType.nonNullable();
     }
-    return null;
   }
 
   bool memberAgreesToCallKind(Member member) {
@@ -79,7 +76,6 @@
       case CallKind.SetFieldInConstructor:
         return member is Field;
     }
-    return false;
   }
 
   String get _callKindPrefix {
@@ -94,7 +90,6 @@
       case CallKind.FieldInitializer:
         return 'init ';
     }
-    return '';
   }
 }
 
@@ -169,7 +164,7 @@
   DynamicSelector(CallKind callKind, this.name) : super(callKind);
 
   @override
-  Member get member => null;
+  Member? get member => null;
 
   @override
   int get hashCode => (super.hashCode ^ name.hashCode + 37) & kHashMask;
@@ -189,7 +184,8 @@
   final List<T> values;
   final List<String> names;
 
-  int _hashCode;
+  @override
+  late final int hashCode = _computeHashCode();
 
   Args(this.values, {this.names = const <String>[]}) {
     assert(isSorted(names));
@@ -206,9 +202,6 @@
 
   T get receiver => values[0];
 
-  @override
-  int get hashCode => _hashCode ??= _computeHashCode();
-
   int _computeHashCode() {
     int hash = 1231;
     for (var v in values) {
diff --git a/pkg/vm/lib/transformations/type_flow/native_code.dart b/pkg/vm/lib/transformations/type_flow/native_code.dart
index 7a5baf9..0611379 100644
--- a/pkg/vm/lib/transformations/type_flow/native_code.dart
+++ b/pkg/vm/lib/transformations/type_flow/native_code.dart
@@ -2,10 +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 file.
 
-// @dart=2.9
-
 /// Handling of native code and entry points.
-library vm.transformations.type_flow.native_code;
 
 import 'dart:core' hide Type;
 
@@ -35,24 +32,21 @@
   /// Record the fact that given member is called from this.
   void recordMemberCalledViaThis(Member target);
 
-  /// Record the fact that given method is torn off.
-  void recordTearOff(Procedure target) {}
+  /// Record the fact that given member is torn off.
+  void recordTearOff(Member target) {}
 }
 
 class PragmaEntryPointsVisitor extends RecursiveVisitor {
   final EntryPointsListener entryPoints;
   final NativeCodeOracle nativeCodeOracle;
   final PragmaAnnotationParser matcher;
-  Class currentClass = null;
 
   PragmaEntryPointsVisitor(
-      this.entryPoints, this.nativeCodeOracle, this.matcher) {
-    assert(matcher != null);
-  }
+      this.entryPoints, this.nativeCodeOracle, this.matcher);
 
-  PragmaEntryPointType _annotationsDefineRoot(List<Expression> annotations) {
+  PragmaEntryPointType? _annotationsDefineRoot(List<Expression> annotations) {
     for (var annotation in annotations) {
-      ParsedPragma pragma = matcher.parsePragma(annotation);
+      ParsedPragma? pragma = matcher.parsePragma(annotation);
       if (pragma == null) continue;
       if (pragma is ParsedEntryPointPragma) return pragma.type;
     }
@@ -72,7 +66,6 @@
       }
       nativeCodeOracle.addClassReferencedFromNativeCode(klass);
     }
-    currentClass = klass;
     klass.visitChildren(this);
   }
 
@@ -88,8 +81,7 @@
       }
       Member target = proc;
       while (target is Procedure && target.isRedirectingFactory) {
-        target = getRedirectingFactoryBody(target).target;
-        assert(target != null);
+        target = getRedirectingFactoryBody(target)!.target!;
         assert(
             (target is Procedure && target.isFactory) || target is Constructor);
       }
@@ -152,7 +144,7 @@
       }
       entryPoints
           .addRawCall(new DirectSelector(ctor, callKind: CallKind.Method));
-      entryPoints.addAllocatedClass(currentClass);
+      entryPoints.addAllocatedClass(ctor.enclosingClass);
       nativeCodeOracle.setMemberReferencedFromNativeCode(ctor);
     }
   }
@@ -201,9 +193,7 @@
   final Set<Class> _classesReferencedFromNativeCode = new Set<Class>();
   final PragmaAnnotationParser _matcher;
 
-  NativeCodeOracle(this._libraryIndex, this._matcher) {
-    assert(_matcher != null);
-  }
+  NativeCodeOracle(this._libraryIndex, this._matcher);
 
   void addClassReferencedFromNativeCode(Class klass) {
     _classesReferencedFromNativeCode.add(klass);
@@ -219,9 +209,9 @@
   bool isMemberReferencedFromNativeCode(Member member) =>
       _membersReferencedFromNativeCode.contains(member);
 
-  PragmaRecognizedType recognizedType(Member member) {
+  PragmaRecognizedType? recognizedType(Member member) {
     for (var annotation in member.annotations) {
-      ParsedPragma pragma = _matcher.parsePragma(annotation);
+      ParsedPragma? pragma = _matcher.parsePragma(annotation);
       if (pragma is ParsedRecognized) {
         return pragma.type;
       }
@@ -229,15 +219,16 @@
     return null;
   }
 
-  bool isRecognized(Member member, [List<PragmaRecognizedType> expectedTypes]) {
-    PragmaRecognizedType type = recognizedType(member);
+  bool isRecognized(Member member,
+      [List<PragmaRecognizedType>? expectedTypes]) {
+    PragmaRecognizedType? type = recognizedType(member);
     return type != null &&
         (expectedTypes == null || expectedTypes.contains(type));
   }
 
   bool hasDisableUnboxedParameters(Member member) {
     for (var annotation in member.annotations) {
-      ParsedPragma pragma = _matcher.parsePragma(annotation);
+      ParsedPragma? pragma = _matcher.parsePragma(annotation);
       if (pragma is ParsedDisableUnboxedParameters) {
         if (member.enclosingLibrary.importUri.scheme != "dart") {
           throw "ERROR: Cannot use @pragma(vm:disable-unboxed-parameters) outside core libraries.";
@@ -255,11 +246,11 @@
       EntryPointsListener entryPointsListener,
       TypesBuilder typesBuilder,
       RuntimeTypeTranslator translator) {
-    TypeExpr returnType = null;
-    bool nullable = null;
+    TypeExpr? returnType = null;
+    bool? nullable = null;
 
     for (var annotation in member.annotations) {
-      ParsedPragma pragma = _matcher.parsePragma(annotation);
+      ParsedPragma? pragma = _matcher.parsePragma(annotation);
       if (pragma == null) continue;
       if (pragma is ParsedResultTypeByTypePragma ||
           pragma is ParsedResultTypeByPathPragma ||
@@ -278,8 +269,8 @@
           returnType = entryPointsListener.addAllocatedClass(type.classNode);
           if (pragma.resultTypeUsesPassedTypeArguments) {
             returnType = translator.instantiateConcreteType(
-                returnType,
-                member.function.typeParameters
+                returnType as ConcreteType,
+                member.function!.typeParameters
                     .map((t) => TypeParameterType(
                         t, TypeParameterType.computeNullabilityFromBound(t)))
                     .toList());
@@ -314,7 +305,7 @@
       return returnType;
     } else {
       return typesBuilder.fromStaticType(
-          member.function.returnType, nullable ?? true);
+          member.function!.returnType, nullable ?? true);
     }
   }
 }
diff --git a/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart b/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart
index a4b0bbc..c0175a4 100644
--- a/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart
+++ b/pkg/vm/lib/transformations/type_flow/protobuf_handler.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
-
 import 'package:kernel/ast.dart';
 import 'package:kernel/clone.dart' show CloneVisitorNotMembers;
 import 'package:kernel/core_types.dart' show CoreTypes;
@@ -47,14 +45,14 @@
   final Procedure _builderInfoAddMethod;
 
   // Type of BuilderInfo.add<Null>().
-  FunctionType _typeOfBuilderInfoAddOfNull;
+  late FunctionType _typeOfBuilderInfoAddOfNull;
 
   final _messageClasses = <Class, _MessageClass>{};
   final _invalidatedClasses = <_MessageClass>{};
 
   /// Creates [ProtobufHandler] instance for [component].
   /// Returns null if protobuf library is not used.
-  static ProtobufHandler forComponent(
+  static ProtobufHandler? forComponent(
       Component component, CoreTypes coreTypes) {
     final libraryIndex = LibraryIndex(component, [protobufLibraryUri]);
     if (!libraryIndex.containsLibrary(protobufLibraryUri)) {
@@ -68,12 +66,12 @@
             libraryIndex.getClass(protobufLibraryUri, 'GeneratedMessage'),
         _tagNumberClass =
             libraryIndex.getClass(protobufLibraryUri, 'TagNumber'),
-        _tagNumberField = libraryIndex.getMember(
-            protobufLibraryUri, 'TagNumber', 'tagNumber'),
+        _tagNumberField =
+            libraryIndex.getField(protobufLibraryUri, 'TagNumber', 'tagNumber'),
         _builderInfoClass =
             libraryIndex.getClass(protobufLibraryUri, 'BuilderInfo'),
-        _builderInfoAddMethod =
-            libraryIndex.getMember(protobufLibraryUri, 'BuilderInfo', 'add') {
+        _builderInfoAddMethod = libraryIndex.getProcedure(
+            protobufLibraryUri, 'BuilderInfo', 'add') {
     final functionType = _builderInfoAddMethod.getterType as FunctionType;
     _typeOfBuilderInfoAddOfNull = Substitution.fromPairs(
             functionType.typeParameters, const <DartType>[NullType()])
@@ -130,8 +128,9 @@
   List<Field> getInvalidatedFields() {
     final fields = <Field>[];
     for (var cls in _invalidatedClasses) {
-      if (cls._metadataField != null) {
-        fields.add(cls._metadataField);
+      final field = cls._metadataField;
+      if (field != null) {
+        fields.add(field);
       }
     }
     _invalidatedClasses.clear();
@@ -143,14 +142,15 @@
     ++Statistics.protobufMetadataInitializersUpdated;
     Statistics.protobufMetadataFieldsPruned -= cls.numberOfFieldsPruned;
 
-    final field = cls._metadataField;
-    if (cls._originalInitializer == null) {
-      cls._originalInitializer = field.initializer;
+    final field = cls._metadataField!;
+    Expression? originalInitializer = cls._originalInitializer;
+    if (originalInitializer == null) {
+      cls._originalInitializer = originalInitializer = field.initializer!;
     }
     final cloner = CloneVisitorNotMembers();
-    field.initializer = cloner.clone(cls._originalInitializer)..parent = field;
+    field.initializer = cloner.clone(originalInitializer)..parent = field;
     final transformer = _MetadataTransformer(this, cls);
-    field.initializer.accept(transformer);
+    field.initializer!.accept(transformer);
     _invalidatedClasses.remove(cls);
 
     cls.numberOfFieldsPruned = transformer.numberOfFieldsPruned;
@@ -168,8 +168,8 @@
 }
 
 class _MessageClass {
-  Field _metadataField;
-  Expression _originalInitializer;
+  Field? _metadataField;
+  Expression? _originalInitializer;
   final _usedTags = <int>{};
   int numberOfFieldsPruned = 0;
 }
diff --git a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
index a61e222..5ae2e16 100644
--- a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
+++ b/pkg/vm/lib/transformations/type_flow/signature_shaking.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
-
 import 'package:kernel/ast.dart';
 import 'package:kernel/external_name.dart';
 import 'package:kernel/type_environment.dart';
@@ -57,7 +55,7 @@
 
   SignatureShaker(this.typeFlowAnalysis, this.tableSelectorAssigner);
 
-  _ProcedureInfo _infoForMember(Member member) {
+  _ProcedureInfo? _infoForMember(Member member) {
     if (!(member is Procedure &&
             (member.kind == ProcedureKind.Method ||
                 member.kind == ProcedureKind.Factory) ||
@@ -89,7 +87,7 @@
     }
     while (worklist.isNotEmpty) {
       _ParameterInfo param = worklist.removeLast();
-      for (_ParameterInfo dependencyParam in param.useDependencies) {
+      for (_ParameterInfo dependencyParam in param.useDependencies!) {
         if (!dependencyParam.isRead) {
           dependencyParam.isRead = true;
           if (dependencyParam.useDependencies != null) {
@@ -141,7 +139,7 @@
     return positional.any((param) =>
             param.canBeEliminated ||
             (param.isAlwaysPassed &&
-                param.index >= function.requiredParameterCount)) ||
+                param.index! >= function.requiredParameterCount)) ||
         named.values
             .any((param) => param.canBeEliminated || param.isAlwaysPassed);
   }
@@ -149,7 +147,7 @@
 
 class _ParameterInfo {
   final _ProcedureInfo info;
-  final int index;
+  final int? index;
 
   int passCount = 0;
   bool isRead = false;
@@ -160,7 +158,7 @@
   /// List of parameter variables which were passed as arguments via this
   /// parameter. When this parameter is considered used, all [useDependencies]
   /// parameters should be transitively marked as read.
-  List<_ParameterInfo> useDependencies = null;
+  List<_ParameterInfo>? useDependencies = null;
 
   _ParameterInfo(this.info, this.index);
 
@@ -177,7 +175,7 @@
 
   void observeParameter(
       Member member, VariableDeclaration param, SignatureShaker shaker) {
-    final Type type = shaker.typeFlowAnalysis.argumentType(member, param);
+    final Type? type = shaker.typeFlowAnalysis.argumentType(member, param);
 
     // A parameter is considered constant if the TFA has inferred it to have a
     // constant value in every implementation. The constant value inferred does
@@ -214,19 +212,19 @@
   _Collect(this.shaker);
 
   void enterFunction(Member member) {
-    final _ProcedureInfo info = shaker._infoForMember(member);
+    final _ProcedureInfo? info = shaker._infoForMember(member);
     if (info == null) return;
 
     localParameters.clear();
     useDependencies.clear();
-    final FunctionNode fun = member.function;
+    final FunctionNode fun = member.function!;
     for (int i = 0; i < fun.positionalParameters.length; i++) {
       final VariableDeclaration param = fun.positionalParameters[i];
       localParameters[param] = info.ensurePositional(i)
         ..observeParameter(member, param, shaker);
     }
     for (VariableDeclaration param in fun.namedParameters) {
-      localParameters[param] = info.ensureNamed(param.name)
+      localParameters[param] = info.ensureNamed(param.name!)
         ..observeParameter(member, param, shaker);
     }
 
@@ -270,19 +268,22 @@
 
   void addUseDependency(Expression arg, _ParameterInfo param) {
     if (arg is VariableGet) {
-      _ParameterInfo localParam = localParameters[arg.variable];
+      _ParameterInfo? localParam = localParameters[arg.variable];
       if (localParam != null && !localParam.isUsed) {
         // This is a parameter passed as an argument. Mark it as a use
         // dependency.
-        param.useDependencies ??= [];
-        param.useDependencies.add(localParam);
+        var paramUseDependencies = param.useDependencies;
+        if (paramUseDependencies == null) {
+          param.useDependencies = paramUseDependencies = [];
+        }
+        paramUseDependencies.add(localParam);
         useDependencies.add(arg);
       }
     }
   }
 
   void collectCall(Member member, Arguments args) {
-    final _ProcedureInfo info = shaker._infoForMember(member);
+    final _ProcedureInfo? info = shaker._infoForMember(member);
     if (info == null) return;
 
     for (int i = 0; i < args.positional.length; i++) {
@@ -306,7 +307,10 @@
 
   @override
   void visitSuperMethodInvocation(SuperMethodInvocation node) {
-    collectCall(node.interfaceTarget, node.arguments);
+    final interfaceTarget = node.interfaceTarget;
+    if (interfaceTarget != null) {
+      collectCall(interfaceTarget, node.arguments);
+    }
     super.visitSuperMethodInvocation(node);
   }
 
@@ -338,7 +342,7 @@
 class _Transform extends RecursiveVisitor {
   final SignatureShaker shaker;
 
-  StaticTypeContext typeContext;
+  late StaticTypeContext typeContext;
   final Map<VariableDeclaration, Constant> eliminatedParams = {};
   final Set<VariableDeclaration> unusedParams = {};
   final List<LocalInitializer> addedInitializers = [];
@@ -349,16 +353,15 @@
       Member member, _ParameterInfo param, VariableDeclaration variable) {
     Constant value;
     if (param.isConstant) {
-      Type type = shaker.typeFlowAnalysis.argumentType(member, variable);
+      Type type = shaker.typeFlowAnalysis.argumentType(member, variable)!;
       if (type is ConcreteType) {
-        assert(type.constant != null);
-        value = type.constant;
+        value = type.constant!;
       } else {
         assert(type is NullableType && type.baseType is EmptyType);
         value = NullConstant();
       }
     } else {
-      value = (variable.initializer as ConstantExpression)?.constant ??
+      value = (variable.initializer as ConstantExpression?)?.constant ??
           NullConstant();
     }
     eliminatedParams[variable] = value;
@@ -370,10 +373,10 @@
     eliminatedParams.clear();
     unusedParams.clear();
 
-    final _ProcedureInfo info = shaker._infoForMember(member);
+    final _ProcedureInfo? info = shaker._infoForMember(member);
     if (info == null || !info.eligible || info.callCount == 0) return;
 
-    final FunctionNode function = member.function;
+    final FunctionNode function = member.function!;
 
     if (!info.transformNeeded(function)) return;
 
@@ -404,9 +407,9 @@
     //    as required positional parameters, alphabetically by name.
     final List<VariableDeclaration> sortedNamed = function.namedParameters
         .toList()
-      ..sort((var1, var2) => var1.name.compareTo(var2.name));
+      ..sort((var1, var2) => var1.name!.compareTo(var2.name!));
     for (VariableDeclaration variable in sortedNamed) {
-      final _ParameterInfo param = info.named[variable.name];
+      final _ParameterInfo param = info.named[variable.name!]!;
       if (param.isAlwaysPassed) {
         if (param.isUsed) {
           if (param.canBeEliminated) {
@@ -451,7 +454,7 @@
     // 4. All named parameters that are not always passed and can't be
     //    eliminated, as named parameters in alphabetical order.
     for (VariableDeclaration variable in sortedNamed) {
-      final _ParameterInfo param = info.named[variable.name];
+      final _ParameterInfo param = info.named[variable.name!]!;
       if (!param.isAlwaysPassed) {
         if (param.isUsed) {
           if (param.canBeEliminated) {
@@ -475,7 +478,7 @@
 
   @override
   void visitVariableGet(VariableGet node) {
-    Constant constantValue = eliminatedParams[node.variable];
+    Constant? constantValue = eliminatedParams[node.variable];
     if (constantValue != null) {
       node.replaceWith(ConstantExpression(constantValue));
     }
@@ -511,7 +514,7 @@
       void Function(Expression, _ParameterInfo) fun) {
     for (int i = args.named.length - 1; i >= 0; i--) {
       final NamedExpression namedExp = args.named[i];
-      fun(namedExp.value, info.named[namedExp.name]);
+      fun(namedExp.value, info.named[namedExp.name]!);
     }
     for (int i = args.positional.length - 1; i >= 0; i--) {
       fun(args.positional[i], info.positional[i]);
@@ -519,8 +522,8 @@
   }
 
   void transformCall(
-      Member target, TreeNode call, Expression receiver, Arguments args) {
-    final _ProcedureInfo info = shaker._infoForMember(target);
+      Member target, TreeNode call, Expression? receiver, Arguments args) {
+    final _ProcedureInfo? info = shaker._infoForMember(target);
     if (info == null || !info.eligible) return;
 
     bool transformNeeded = false;
@@ -544,7 +547,7 @@
     Map<Expression, VariableDeclaration> hoisted = {};
     if (hoistingNeeded) {
       if (call is Initializer) {
-        final Constructor constructor = call.parent;
+        final Constructor constructor = call.parent as Constructor;
         forEachArgumentRev(args, info, (Expression arg, _ParameterInfo param) {
           if (mayHaveOrSeeSideEffects(arg) && !isUnusedParam(arg)) {
             VariableDeclaration argVar = VariableDeclaration(null,
@@ -557,8 +560,8 @@
           }
         });
       } else {
-        final TreeNode parent = call.parent;
-        Expression current = call;
+        final TreeNode parent = call.parent!;
+        Expression current = call as Expression;
         forEachArgumentRev(args, info, (Expression arg, _ParameterInfo param) {
           if (mayHaveOrSeeSideEffects(arg) && !isUnusedParam(arg)) {
             VariableDeclaration argVar = VariableDeclaration(null,
@@ -606,7 +609,7 @@
     final List<NamedExpression> sortedNamed = args.named.toList()
       ..sort((var1, var2) => var1.name.compareTo(var2.name));
     for (NamedExpression arg in sortedNamed) {
-      final _ParameterInfo param = info.named[arg.name];
+      final _ParameterInfo param = info.named[arg.name]!;
       if (param.isAlwaysPassed && !param.canBeEliminated) {
         positional.add(getMaybeHoistedArg(arg.value));
       }
@@ -625,7 +628,7 @@
     //    eliminated, as named parameters in alphabetical order.
     //    (Arguments are kept in original order.)
     for (NamedExpression arg in args.named) {
-      final _ParameterInfo param = info.named[arg.name];
+      final _ParameterInfo param = info.named[arg.name]!;
       if (!param.isAlwaysPassed && !param.canBeEliminated) {
         arg.value = getMaybeHoistedArg(arg.value)..parent = arg;
         named.add(arg);
@@ -644,7 +647,10 @@
   @override
   void visitSuperMethodInvocation(SuperMethodInvocation node) {
     super.visitSuperMethodInvocation(node);
-    transformCall(node.interfaceTarget, node, null, node.arguments);
+    final interfaceTarget = node.interfaceTarget;
+    if (interfaceTarget != null) {
+      transformCall(interfaceTarget, node, null, node.arguments);
+    }
   }
 
   @override
diff --git a/pkg/vm/lib/transformations/type_flow/summary.dart b/pkg/vm/lib/transformations/type_flow/summary.dart
index dcae2df..fb18cec 100644
--- a/pkg/vm/lib/transformations/type_flow/summary.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary.dart
@@ -2,10 +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 file.
 
-// @dart=2.9
-
 /// Type flow summary of a member, function or initializer.
-library vm.transformations.type_flow.summary;
 
 import 'dart:core' hide Type;
 
@@ -18,7 +15,7 @@
 
 abstract class CallHandler {
   Type applyCall(Call callSite, Selector selector, Args<Type> args,
-      {bool isResultUsed});
+      {required bool isResultUsed});
   void typeCheckTriggered();
   void addAllocatedClass(Class c);
 }
@@ -27,14 +24,10 @@
 abstract class Statement extends TypeExpr {
   /// Index of this statement in the [Summary].
   int index = -1;
-  Summary summary;
+  late Summary summary;
 
   @override
-  Type getComputedType(List<Type> types) {
-    final type = types[index];
-    assert(type != null);
-    return type;
-  }
+  Type getComputedType(List<Type?> types) => types[index]!;
 
   String get label => "t$index";
 
@@ -48,7 +41,7 @@
   void accept(StatementVisitor visitor);
 
   /// Execute this statement and compute its resulting type.
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
       CallHandler callHandler);
 }
 
@@ -74,9 +67,9 @@
   // [staticType] is null if no narrowing should be performed. This happens for
   // type parameters and for parameters whose type is narrowed by a [TypeCheck]
   // statement.
-  final Type staticTypeForNarrowing;
+  final Type? staticTypeForNarrowing;
 
-  Type defaultValue;
+  Type? defaultValue;
   Type _argumentType = const EmptyType();
 
   Parameter(this.name, this.staticTypeForNarrowing);
@@ -97,7 +90,7 @@
   }
 
   @override
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
           CallHandler callHandler) =>
       throw 'Unable to apply _Parameter';
 
@@ -110,7 +103,7 @@
   }
 
   Type _observeNotPassed(TypeHierarchy typeHierarchy) {
-    final Type argType = defaultValue.specialize(typeHierarchy);
+    final Type argType = defaultValue!.specialize(typeHierarchy);
     _observeArgumentType(argType, typeHierarchy);
     return argType;
   }
@@ -130,7 +123,7 @@
   String dump() => "$label = _Narrow ($arg to $type)";
 
   @override
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
           CallHandler callHandler) =>
       arg.getComputedType(computedTypes).intersection(type, typeHierarchy);
 }
@@ -147,11 +140,11 @@
 
   // Shared NarrowNotNull instances which are used when the outcome is
   // known at summary creation time.
-  static final NarrowNotNull alwaysNotNull = NarrowNotNull(null)
+  static final NarrowNotNull alwaysNotNull = NarrowNotNull(const EmptyType())
     .._flags = canBeNotNullFlag;
-  static final NarrowNotNull alwaysNull = NarrowNotNull(null)
+  static final NarrowNotNull alwaysNull = NarrowNotNull(const EmptyType())
     .._flags = canBeNullFlag;
-  static final NarrowNotNull unknown = NarrowNotNull(null)
+  static final NarrowNotNull unknown = NarrowNotNull(const EmptyType())
     .._flags = canBeNullFlag | canBeNotNullFlag;
 
   bool get isAlwaysNull => (_flags & canBeNotNullFlag) == 0;
@@ -173,14 +166,14 @@
   }
 
   @override
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
           CallHandler callHandler) =>
       handleArgument(arg.getComputedType(computedTypes));
 }
 
 /// Joins values from multiple sources. Its type is a union of [values].
 class Join extends Statement {
-  final String _name;
+  final String? _name;
   final DartType staticType;
   final List<TypeExpr> values = <TypeExpr>[]; // TODO(alexmarkov): Set
 
@@ -197,15 +190,14 @@
       " (${values.join(", ")})";
 
   @override
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
       CallHandler callHandler) {
-    Type type = null;
-    assert(values.isNotEmpty);
+    Type? type = null;
     for (var value in values) {
       final valueType = value.getComputedType(computedTypes);
       type = type != null ? type.union(valueType, typeHierarchy) : valueType;
     }
-    return type;
+    return type!;
   }
 }
 
@@ -222,7 +214,7 @@
   String dump() => "$label = _Use ($arg)";
 
   @override
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
           CallHandler callHandler) =>
       throw 'Use statements should be removed during summary normalization';
 }
@@ -231,7 +223,7 @@
 class Call extends Statement {
   final Selector selector;
   final Args<TypeExpr> args;
-  final Type staticResultType;
+  final Type? staticResultType;
 
   Call(this.selector, this.args, this.staticResultType,
       bool isInstanceCreation) {
@@ -252,9 +244,10 @@
   String dump() => "$label${isResultUsed ? '*' : ''} = _Call $selector $args";
 
   @override
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
       CallHandler callHandler) {
-    final List<Type> argTypes = new List<Type>.filled(args.values.length, null);
+    final List<Type> argTypes =
+        new List<Type>.filled(args.values.length, const EmptyType());
     for (int i = 0; i < args.values.length; i++) {
       final Type type = args.values[i].getComputedType(computedTypes);
       if (type == const EmptyType()) {
@@ -271,14 +264,15 @@
       callHandler
           .addAllocatedClass((argTypes[0] as ConcreteType).cls.classNode);
     }
-    final Stopwatch timer = kPrintTimings ? (new Stopwatch()..start()) : null;
+    final Stopwatch? timer = kPrintTimings ? (new Stopwatch()..start()) : null;
     Type result = callHandler.applyCall(
         this, selector, new Args<Type>(argTypes, names: args.names),
         isResultUsed: isResultUsed);
-    summary.calleeTime += kPrintTimings ? timer.elapsedMicroseconds : 0;
+    summary.calleeTime += kPrintTimings ? timer!.elapsedMicroseconds : 0;
     if (isInstanceCreation) {
       result = argTypes[0];
     } else if (isResultUsed) {
+      final staticResultType = this.staticResultType;
       if (staticResultType != null) {
         result = result.intersection(staticResultType, typeHierarchy);
       }
@@ -302,9 +296,9 @@
   static const int kReceiverMayBeInt = (1 << 6);
   static const int kInstanceCreation = (1 << 7);
 
-  Member _monomorphicTarget;
+  Member? _monomorphicTarget;
 
-  Member get monomorphicTarget => _monomorphicTarget;
+  Member? get monomorphicTarget => _monomorphicTarget;
 
   bool get isMonomorphic => (_flags & kMonomorphic) != 0;
 
@@ -396,18 +390,19 @@
       "/$paramIndex]${nullability.suffix})";
 
   @override
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
       CallHandler callHandler) {
     Type argType = arg.getComputedType(computedTypes);
-    Type extractedType;
+    Type? extractedType;
 
     void extractType(ConcreteType c) {
-      if (c.typeArgs == null) {
+      final typeArgs = c.typeArgs;
+      if (typeArgs == null) {
         extractedType = const UnknownType();
       } else {
         final interfaceOffset = typeHierarchy.genericInterfaceOffsetFor(
             c.cls.classNode, referenceClass);
-        final typeArg = c.typeArgs[interfaceOffset + paramIndex];
+        final typeArg = typeArgs[interfaceOffset + paramIndex];
         Type extracted = typeArg;
         if (typeArg is RuntimeType) {
           final argNullability = typeArg.nullability;
@@ -472,16 +467,15 @@
   }
 
   @override
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
       CallHandler callHandler) {
     bool hasRuntimeType = false;
-    final types = new List<Type>.filled(flattenedTypeArgs.length, null);
-    for (int i = 0; i < types.length; ++i) {
+    final types = List<Type>.generate(flattenedTypeArgs.length, (int i) {
       final computed = flattenedTypeArgs[i].getComputedType(computedTypes);
       assert(computed is RuntimeType || computed is UnknownType);
       if (computed is RuntimeType) hasRuntimeType = true;
-      types[i] = computed;
-    }
+      return computed;
+    });
     return new ConcreteType(cls, hasRuntimeType ? types : null);
   }
 }
@@ -505,14 +499,13 @@
       "${nullability.suffix})";
 
   @override
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
       CallHandler callHandler) {
-    final types = new List<RuntimeType>.filled(flattenedTypeArgs.length, null);
-    for (int i = 0; i < types.length; ++i) {
-      final computed = flattenedTypeArgs[i].getComputedType(computedTypes);
-      assert(computed is RuntimeType || computed is UnknownType);
+    final types = <RuntimeType>[];
+    for (TypeExpr arg in flattenedTypeArgs) {
+      final computed = arg.getComputedType(computedTypes);
       if (computed is UnknownType) return const UnknownType();
-      types[i] = computed;
+      types.add(computed as RuntimeType);
     }
     DartType dartType;
     if (klass == typeHierarchy.coreTypes.deprecatedFutureOrClass) {
@@ -545,17 +538,15 @@
   // "unchecked" entrypoint.
   bool isTestedOnlyOnCheckedEntryPoint;
 
-  VariableDeclaration get parameter =>
-      node is VariableDeclaration ? node : null;
+  bool get isParameterCheck => node is VariableDeclaration;
+  VariableDeclaration get parameterVariable => node as VariableDeclaration;
 
   bool alwaysPass = true;
   bool alwaysFail = true;
 
-  TypeCheck(this.arg, this.type, this.node, this.staticType, this.kind) {
-    assert(node != null);
-    isTestedOnlyOnCheckedEntryPoint =
-        parameter != null && !parameter.isCovariant;
-  }
+  TypeCheck(this.arg, this.type, this.node, this.staticType, this.kind)
+      : isTestedOnlyOnCheckedEntryPoint =
+            node is VariableDeclaration && !node.isCovariant;
 
   @override
   void accept(StatementVisitor visitor) => visitor.visitTypeCheck(this);
@@ -568,7 +559,7 @@
   }
 
   @override
-  Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
+  Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
       CallHandler callHandler) {
     Type argType = arg.getComputedType(computedTypes);
     Type checkType = type.getComputedType(computedTypes);
@@ -624,11 +615,11 @@
   int requiredParameterCount;
 
   List<Statement> _statements = <Statement>[];
-  TypeExpr result = null;
-  Type resultType = EmptyType();
+  TypeExpr result = const EmptyType();
+  Type resultType = const EmptyType();
 
   // Analysis time of callees. Populated only if kPrintTimings.
-  int calleeTime;
+  int calleeTime = 0;
 
   Summary(this.name,
       {this.parameterCount: 0,
@@ -658,7 +649,7 @@
   /// Apply this summary to the given arguments and return the resulting type.
   Type apply(Args<Type> arguments, TypeHierarchy typeHierarchy,
       CallHandler callHandler) {
-    final Stopwatch timer = kPrintTimings ? (new Stopwatch()..start()) : null;
+    final Stopwatch? timer = kPrintTimings ? (new Stopwatch()..start()) : null;
     final int oldCalleeTime = calleeTime;
     calleeTime = 0;
     final args = arguments.values;
@@ -677,7 +668,7 @@
     //
     // The first `parameterCount` statements are Parameters.
 
-    List<Type> types = new List<Type>.filled(_statements.length, null);
+    List<Type?> types = new List<Type?>.filled(_statements.length, null);
 
     for (int i = 0; i < positionalArgCount; i++) {
       final Parameter param = _statements[i] as Parameter;
@@ -687,9 +678,9 @@
       }
       final argType = args[i].specialize(typeHierarchy);
       param._observeArgumentType(argType, typeHierarchy);
-      if (param.staticTypeForNarrowing != null) {
-        types[i] =
-            argType.intersection(param.staticTypeForNarrowing, typeHierarchy);
+      final staticTypeForNarrowing = param.staticTypeForNarrowing;
+      if (staticTypeForNarrowing != null) {
+        types[i] = argType.intersection(staticTypeForNarrowing, typeHierarchy);
       } else {
         // TODO(sjindel/tfa): Narrowing is performed inside a [TypeCheck] later.
         types[i] = args[i];
@@ -710,9 +701,10 @@
             args[positionalArgCount + argIndex].specialize(typeHierarchy);
         argIndex++;
         param._observeArgumentType(argType, typeHierarchy);
-        if (param.staticTypeForNarrowing != null) {
+        final staticTypeForNarrowing = param.staticTypeForNarrowing;
+        if (staticTypeForNarrowing != null) {
           types[i] =
-              argType.intersection(param.staticTypeForNarrowing, typeHierarchy);
+              argType.intersection(staticTypeForNarrowing, typeHierarchy);
         } else {
           types[i] = argType;
         }
@@ -741,7 +733,7 @@
     resultType = resultType.union(computedType, typeHierarchy);
 
     if (kPrintTimings) {
-      final dirtyTime = timer.elapsedMicroseconds;
+      final dirtyTime = timer!.elapsedMicroseconds;
       final pureTime = dirtyTime < calleeTime ? 0 : (dirtyTime - calleeTime);
       Statistics.numSummaryApplications.add(name);
       Statistics.dirtySummaryAnalysisTime.add(name, dirtyTime);
@@ -753,9 +745,9 @@
   }
 
   Args<Type> get argumentTypes {
-    final argTypes = new List<Type>.filled(parameterCount, null);
-    final argNames = new List<String>.filled(
-        parameterCount - positionalParameterCount, null);
+    final argTypes = new List<Type>.filled(parameterCount, const EmptyType());
+    final argNames =
+        new List<String>.filled(parameterCount - positionalParameterCount, '');
     for (int i = 0; i < parameterCount; i++) {
       Parameter param = _statements[i] as Parameter;
       argTypes[i] = param.argumentType;
@@ -769,7 +761,7 @@
   Type argumentType(Member member, VariableDeclaration memberParam) {
     final int firstParamIndex =
         numTypeParams(member) + (hasReceiverArg(member) ? 1 : 0);
-    final positional = member.function.positionalParameters;
+    final positional = member.function!.positionalParameters;
     for (int i = 0; i < positional.length; i++) {
       if (positional[i] == memberParam) {
         final Parameter param = _statements[firstParamIndex + i] as Parameter;
@@ -791,8 +783,8 @@
     for (Statement statement in _statements) {
       if (statement is TypeCheck &&
           statement.alwaysPass &&
-          statement.parameter != null) {
-        params.add(statement.parameter);
+          statement.isParameterCheck) {
+        params.add(statement.parameterVariable);
       }
     }
     return params;
@@ -808,17 +800,17 @@
         (hasReceiverArg(member) ? 1 : 0) + numTypeParams(member);
     final Map<String, Parameter> paramsByName = {};
     for (int i = implicit; i < parameterCount; i++) {
-      final Parameter param = statements[i];
+      final Parameter param = statements[i] as Parameter;
       paramsByName[param.name] = param;
     }
-    FunctionNode function = member.function;
+    FunctionNode function = member.function!;
     statements.length = implicit;
     for (VariableDeclaration param in function.positionalParameters) {
-      statements.add(paramsByName[param.name]);
+      statements.add(paramsByName[param.name]!);
     }
     positionalParameterCount = statements.length;
     for (VariableDeclaration param in function.namedParameters) {
-      statements.add(paramsByName[param.name]);
+      statements.add(paramsByName[param.name]!);
     }
     parameterCount = statements.length;
     requiredParameterCount = implicit + function.requiredParameterCount;
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index cd78792..d2157f7 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -2,10 +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 file.
 
-// @dart=2.9
-
 /// Creation of type flow summaries out of kernel AST.
-library vm.transformations.type_flow.summary_collector;
 
 import 'dart:core' hide Type;
 
@@ -14,6 +11,7 @@
 import 'package:kernel/ast.dart' as ast show Statement, StatementVisitor;
 import 'package:kernel/class_hierarchy.dart'
     show ClassHierarchy, ClosedWorldClassHierarchy;
+import 'package:kernel/core_types.dart' show CoreTypes;
 import 'package:kernel/type_environment.dart'
     show StaticTypeContext, SubtypeCheckMode, TypeEnvironment;
 import 'package:kernel/type_algebra.dart' show Substitution;
@@ -239,7 +237,7 @@
   // function and checks if control can fall through them or not.
 
   bool controlCanFallThrough(FunctionNode function) {
-    return function.body.accept(this);
+    return function.body!.accept(this);
   }
 
   @override
@@ -285,11 +283,11 @@
   bool visitContinueSwitchStatement(ContinueSwitchStatement node) => false;
 
   @override
-  bool visitIfStatement(IfStatement node) =>
-      node.then == null ||
-      node.otherwise == null ||
-      node.then.accept(this) ||
-      node.otherwise.accept(this);
+  bool visitIfStatement(IfStatement node) {
+    final otherwise = node.otherwise;
+    if (otherwise == null) return true;
+    return node.then.accept(this) || otherwise.accept(this);
+  }
 
   @override
   bool visitReturnStatement(ReturnStatement node) => false;
@@ -323,7 +321,7 @@
   final List<VariableDeclaration> varDeclarations = <VariableDeclaration>[];
 
   /// Set of captured variables.
-  Set<VariableDeclaration> captured;
+  Set<VariableDeclaration>? captured;
 
   /// Set of variables which were modified for each loop, switch statement
   /// and try block statement. Doesn't include captured variables and
@@ -334,10 +332,10 @@
   int numVariablesAtFunctionEntry = 0;
 
   /// Active loops, switch statements and try blocks.
-  List<ast.Statement> activeStatements;
+  List<ast.Statement>? activeStatements;
 
   /// Number of variables at entry of active statements.
-  List<int> numVariablesAtActiveStatements;
+  List<int>? numVariablesAtActiveStatements;
 
   _VariablesInfoCollector(Member member) {
     member.accept(this);
@@ -345,8 +343,10 @@
 
   int get numVariables => varDeclarations.length;
 
-  bool isCaptured(VariableDeclaration variable) =>
-      captured != null && captured.contains(variable);
+  bool isCaptured(VariableDeclaration variable) {
+    final captured = this.captured;
+    return captured != null && captured.contains(variable);
+  }
 
   Set<int> getModifiedVariables(ast.Statement st) {
     return modifiedSets[st] ?? const <int>{};
@@ -387,14 +387,15 @@
   }
 
   void _useVariable(VariableDeclaration variable, bool isVarAssignment) {
-    final index = varIndex[variable];
+    final index = varIndex[variable]!;
     if (_isDeclaredBefore(index, numVariablesAtFunctionEntry)) {
       _captureVariable(variable);
       return;
     }
+    final activeStatements = this.activeStatements;
     if (isVarAssignment && activeStatements != null) {
       for (int i = activeStatements.length - 1; i >= 0; --i) {
-        if (_isDeclaredBefore(index, numVariablesAtActiveStatements[i])) {
+        if (_isDeclaredBefore(index, numVariablesAtActiveStatements![i])) {
           final st = activeStatements[i];
           (modifiedSets[st] ??= <int>{}).add(index);
         } else {
@@ -410,8 +411,8 @@
   }
 
   void _endCollectingModifiedVariables() {
-    activeStatements.removeLast();
-    numVariablesAtActiveStatements.removeLast();
+    activeStatements!.removeLast();
+    numVariablesAtActiveStatements!.removeLast();
   }
 
   @override
@@ -457,7 +458,7 @@
   @override
   visitTryCatch(TryCatch node) {
     _startCollectingModifiedVariables(node);
-    node.body?.accept(this);
+    node.body.accept(this);
     _endCollectingModifiedVariables();
     visitList(node.catches, this);
   }
@@ -465,9 +466,9 @@
   @override
   visitTryFinally(TryFinally node) {
     _startCollectingModifiedVariables(node);
-    node.body?.accept(this);
+    node.body.accept(this);
     _endCollectingModifiedVariables();
-    node.finalizer?.accept(this);
+    node.finalizer.accept(this);
   }
 
   @override
@@ -489,7 +490,7 @@
     visitList(node.variables, this);
     _startCollectingModifiedVariables(node);
     node.condition?.accept(this);
-    node.body?.accept(this);
+    node.body.accept(this);
     visitList(node.updates, this);
     _endCollectingModifiedVariables();
   }
@@ -521,7 +522,7 @@
 enum FieldSummaryType { kFieldGuard, kInitializer }
 
 /// Create a type flow summary for a member from the kernel AST.
-class SummaryCollector extends RecursiveResultVisitor<TypeExpr> {
+class SummaryCollector extends RecursiveResultVisitor<TypeExpr?> {
   final Target target;
   final TypeEnvironment _environment;
   final ClosedWorldClassHierarchy _hierarchy;
@@ -529,7 +530,7 @@
   final TypesBuilder _typesBuilder;
   final NativeCodeOracle _nativeCodeOracle;
   final GenericInterfacesInfo _genericInterfacesInfo;
-  final ProtobufHandler _protobufHandler;
+  final ProtobufHandler? _protobufHandler;
 
   final Map<TreeNode, Call> callSites = <TreeNode, Call>{};
   final Map<AsExpression, TypeCheck> explicitCasts =
@@ -540,13 +541,13 @@
   final Set<Name> _nullMethodsAndGetters = <Name>{};
   final Set<Name> _nullSetters = <Name>{};
 
-  Summary _summary;
-  _VariablesInfoCollector _variablesInfo;
+  Summary _summary = Summary('<unused>');
+  late _VariablesInfoCollector _variablesInfo;
 
   // Current value of each variable. May contain null if variable is not
   // declared yet, or EmptyType if current location is unreachable
   // (e.g. after return or throw).
-  List<TypeExpr> _variableValues;
+  List<TypeExpr?> _variableValues = const <TypeExpr?>[];
 
   // Contains Joins which accumulate all values of certain variables.
   // Used only when all variable values should be merged regardless of control
@@ -558,30 +559,30 @@
   // If _variableCells[i] != null, then all values are accumulated in the
   // _variableCells[i]. _variableValues[i] does not change and remains equal
   // to _variableCells[i].
-  List<Join> _variableCells;
+  List<Join?> _variableCells = const <Join?>[];
 
   // Counts number of Joins inserted for each variable. Only used to set
   // readable names for such joins (foo_0, foo_1 etc.)
-  List<int> _variableVersions;
+  List<int> _variableVersions = const <int>[];
 
   // State of variables after corresponding LabeledStatement.
   // Used to collect states from BreakStatements.
-  Map<LabeledStatement, List<TypeExpr>> _variableValuesAfterLabeledStatements;
+  Map<LabeledStatement, List<TypeExpr?>>? _variableValuesAfterLabeledStatements;
 
   // Joins corresponding to variables on entry to switch cases.
   // Used to propagate state from ContinueSwitchStatement to a target case.
-  Map<SwitchCase, List<Join>> _joinsAtSwitchCases;
+  Map<SwitchCase, List<Join?>>? _joinsAtSwitchCases;
 
   // Join which accumulates all return values.
-  Join _returnValue;
+  Join? _returnValue;
 
-  Parameter _receiver;
-  ConstantAllocationCollector constantAllocationCollector;
-  RuntimeTypeTranslatorImpl _translator;
-  StaticTypeContext _staticTypeContext;
+  Parameter? _receiver;
+  late ConstantAllocationCollector constantAllocationCollector;
+  late RuntimeTypeTranslatorImpl _translator;
+  StaticTypeContext? _staticTypeContext;
 
   // Currently only used for factory constructors.
-  Map<TypeParameter, TypeExpr> _fnTypeVariables;
+  Map<TypeParameter, TypeExpr>? _fnTypeVariables;
 
   SummaryCollector(
       this.target,
@@ -592,7 +593,6 @@
       this._nativeCodeOracle,
       this._genericInterfacesInfo,
       this._protobufHandler) {
-    assert(_genericInterfacesInfo != null);
     constantAllocationCollector = new ConstantAllocationCollector(this);
     _nullMethodsAndGetters.addAll(getSelectors(
         _hierarchy, _environment.coreTypes.deprecatedNullClass,
@@ -615,8 +615,8 @@
     _staticTypeContext = new StaticTypeContext(member, _environment);
     _variablesInfo = new _VariablesInfoCollector(member);
     _variableValues =
-        new List<TypeExpr>.filled(_variablesInfo.numVariables, null);
-    _variableCells = new List<Join>.filled(_variablesInfo.numVariables, null);
+        new List<TypeExpr?>.filled(_variablesInfo.numVariables, null);
+    _variableCells = new List<Join?>.filled(_variablesInfo.numVariables, null);
     _variableVersions = new List<int>.filled(_variablesInfo.numVariables, 0);
     _variableValuesAfterLabeledStatements = null;
     _joinsAtSwitchCases = null;
@@ -633,25 +633,24 @@
             parameterCount: numArgs, positionalParameterCount: numArgs);
         // TODO(alexmarkov): subclass cone
         _receiver = _declareParameter("this",
-            _environment.coreTypes.legacyRawType(member.enclosingClass), null,
+            _environment.coreTypes.legacyRawType(member.enclosingClass!), null,
             isReceiver: true);
       } else {
         _summary = new Summary(summaryName);
       }
 
-      _translator = new RuntimeTypeTranslatorImpl(
-          this, _summary, _receiver, null, _genericInterfacesInfo);
+      _translator = new RuntimeTypeTranslatorImpl(_environment.coreTypes,
+          _summary, _receiver, null, _genericInterfacesInfo);
 
       if (fieldSummaryType == FieldSummaryType.kInitializer) {
-        assert(member.initializer != null);
-        _summary.result = _visit(member.initializer);
+        _summary.result = _visit(member.initializer!);
       } else {
         final Parameter valueParam =
             _declareParameter("value", member.type, null);
         _summary.result = _typeCheck(valueParam, member.type, member);
       }
     } else {
-      FunctionNode function = member.function;
+      final FunctionNode function = member.function!;
 
       final numTypeParameters = numTypeParams(member);
       final firstParamIndex = (hasReceiver ? 1 : 0) + numTypeParameters;
@@ -666,43 +665,42 @@
               firstParamIndex + function.requiredParameterCount);
 
       if (numTypeParameters > 0) {
-        _fnTypeVariables = <TypeParameter, TypeExpr>{};
-        for (int i = 0; i < numTypeParameters; ++i) {
-          _fnTypeVariables[function.typeParameters[i]] =
-              _declareParameter(function.typeParameters[i].name, null, null);
-        }
+        _fnTypeVariables = <TypeParameter, TypeExpr>{
+          for (TypeParameter tp in function.typeParameters)
+            tp: _declareParameter(tp.name!, null, null)
+        };
       }
 
       if (hasReceiver) {
         // TODO(alexmarkov): subclass cone
         _receiver = _declareParameter("this",
-            _environment.coreTypes.legacyRawType(member.enclosingClass), null,
+            _environment.coreTypes.legacyRawType(member.enclosingClass!), null,
             isReceiver: true);
       }
 
-      _translator = new RuntimeTypeTranslatorImpl(
-          this, _summary, _receiver, _fnTypeVariables, _genericInterfacesInfo);
+      _translator = new RuntimeTypeTranslatorImpl(_environment.coreTypes,
+          _summary, _receiver, _fnTypeVariables, _genericInterfacesInfo);
 
       // Handle forwarding stubs. We need to check types against the types of
       // the forwarding stub's target, [member.concreteForwardingStubTarget].
-      FunctionNode useTypesFrom = member.function;
-      if (member is Procedure &&
-          member.isForwardingStub &&
-          member.concreteForwardingStubTarget != null) {
+      FunctionNode useTypesFrom = function;
+      if (member is Procedure && member.isForwardingStub) {
         final target = member.concreteForwardingStubTarget;
-        if (target is Field) {
-          useTypesFrom = FunctionNode(null, positionalParameters: [
-            VariableDeclaration("value", type: target.type)
-          ]);
-        } else {
-          useTypesFrom = member.concreteForwardingStubTarget.function;
+        if (target != null) {
+          if (target is Field) {
+            useTypesFrom = FunctionNode(null, positionalParameters: [
+              VariableDeclaration("value", type: target.type)
+            ]);
+          } else {
+            useTypesFrom = target.function!;
+          }
         }
       }
 
       for (int i = 0; i < function.positionalParameters.length; ++i) {
         final decl = function.positionalParameters[i];
         _declareParameter(
-            decl.name,
+            decl.name!,
             _useTypeCheckForParameter(decl)
                 ? null
                 : useTypesFrom.positionalParameters[i].type,
@@ -711,7 +709,7 @@
       for (int i = 0; i < function.namedParameters.length; ++i) {
         final decl = function.namedParameters[i];
         _declareParameter(
-            decl.name,
+            decl.name!,
             _useTypeCheckForParameter(decl)
                 ? null
                 : useTypesFrom.namedParameters[i].type,
@@ -740,7 +738,7 @@
       assert(count == _summary.parameterCount);
 
       _returnValue = new Join("%result", function.returnType);
-      _summary.add(_returnValue);
+      _summary.add(_returnValue!);
 
       if (member is Constructor) {
         // Make sure instance field initializers are visited.
@@ -750,7 +748,7 @@
                 new DirectSelector(f, callKind: CallKind.FieldInitializer));
           }
         }
-        member.initializers.forEach(_visit);
+        member.initializers.forEach(_visitWithoutResult);
       }
 
       if (function.body == null) {
@@ -760,15 +758,15 @@
           // Runtime type could be more precise than static type, so
           // calculate intersection.
           final typeCheck = _typeCheck(type, function.returnType, function);
-          _returnValue.values.add(typeCheck);
+          _returnValue!.values.add(typeCheck);
         } else {
-          _returnValue.values.add(type);
+          _returnValue!.values.add(type);
         }
       } else {
-        _visit(function.body);
+        _visitWithoutResult(function.body!);
 
         if (_fallthroughDetector.controlCanFallThrough(function)) {
-          _returnValue.values.add(_nullType);
+          _returnValue!.values.add(_nullType);
         }
       }
 
@@ -776,15 +774,15 @@
         // In addition to what is returned from the function body,
         // operator == performs implicit comparison with null
         // and returns bool.
-        _returnValue.values.add(_boolType);
+        _returnValue!.values.add(_boolType);
       }
 
-      _summary.result = _returnValue;
+      _summary.result = _returnValue!;
     }
 
     member.annotations.forEach(_visit);
-    member.enclosingClass?.annotations?.forEach(_visit);
-    member.enclosingLibrary?.annotations?.forEach(_visit);
+    member.enclosingClass?.annotations.forEach(_visit);
+    member.enclosingLibrary.annotations.forEach(_visit);
 
     _staticTypeContext = null;
 
@@ -808,9 +806,7 @@
   }
 
   Args<Type> rawArguments(Selector selector) {
-    final member = selector.member;
-    assert(member != null);
-
+    final member = selector.member!;
     final List<Type> args = <Type>[];
     final List<String> names = <String>[];
 
@@ -822,15 +818,14 @@
     if (hasReceiverArg(member)) {
       assert(member.enclosingClass != null);
       final receiver =
-          new ConeType(_typesBuilder.getTFClass(member.enclosingClass));
+          new ConeType(_typesBuilder.getTFClass(member.enclosingClass!));
       args.add(receiver);
     }
 
     switch (selector.callKind) {
       case CallKind.Method:
         if (member is! Field) {
-          final function = member.function;
-          assert(function != null);
+          final function = member.function!;
 
           final int paramCount = function.positionalParameters.length +
               function.namedParameters.length;
@@ -840,7 +835,7 @@
 
           if (function.namedParameters.isNotEmpty) {
             for (var param in function.namedParameters) {
-              names.add(param.name);
+              names.add(param.name!);
             }
             // TODO(dartbug.com/32292): make sure parameters are sorted in
             // kernel AST and remove this sorting.
@@ -864,11 +859,15 @@
     return new Args<Type>(args, names: names);
   }
 
-  TypeExpr _visit(TreeNode node) => node.accept(this);
+  TypeExpr _visit(Expression node) => node.accept(this)!;
 
-  Args<TypeExpr> _visitArguments(TypeExpr receiver, Arguments arguments,
+  void _visitWithoutResult(TreeNode node) {
+    node.accept(this);
+  }
+
+  Args<TypeExpr> _visitArguments(TypeExpr? receiver, Arguments arguments,
       {bool passTypeArguments: false}) {
-    final args = <TypeExpr>[];
+    final List<TypeExpr> args = <TypeExpr>[];
     if (passTypeArguments) {
       for (var type in arguments.types) {
         args.add(_translator.translate(type));
@@ -890,7 +889,7 @@
       }
       names.sort();
       for (var name in names) {
-        args.add(map[name]);
+        args.add(map[name]!);
       }
       return new Args<TypeExpr>(args, names: names);
     } else {
@@ -899,9 +898,9 @@
   }
 
   Parameter _declareParameter(
-      String name, DartType type, Expression initializer,
+      String name, DartType? type, Expression? initializer,
       {bool isReceiver: false}) {
-    Type staticType;
+    Type? staticType;
     if (type != null) {
       staticType = _typesBuilder.fromStaticType(type, !isReceiver);
     }
@@ -916,7 +915,7 @@
         } else if (initializer is BasicLiteral ||
             initializer is SymbolLiteral ||
             initializer is TypeLiteral) {
-          param.defaultValue = _visit(initializer);
+          param.defaultValue = _visit(initializer) as Type;
         } else {
           throw 'Unexpected parameter $name default value ${initializer.runtimeType} $initializer';
         }
@@ -930,8 +929,7 @@
   }
 
   void _declareVariable(VariableDeclaration decl, TypeExpr initialValue) {
-    final int varIndex = _variablesInfo.varIndex[decl];
-    assert(varIndex != null);
+    final int varIndex = _variablesInfo.varIndex[decl]!;
     assert(_variablesInfo.varDeclarations[varIndex] == decl);
     assert(_variableValues[varIndex] == null);
     if (_variablesInfo.isCaptured(decl)) {
@@ -944,8 +942,8 @@
   }
 
   void _writeVariable(VariableDeclaration variable, TypeExpr value) {
-    final int varIndex = _variablesInfo.varIndex[variable];
-    final Join join = _variableCells[varIndex];
+    final int varIndex = _variablesInfo.varIndex[variable]!;
+    final Join? join = _variableCells[varIndex];
     if (join != null) {
       join.values.add(value);
     } else {
@@ -953,11 +951,12 @@
     }
   }
 
-  List<TypeExpr> _cloneVariableValues(List<TypeExpr> values) =>
-      new List<TypeExpr>.from(values);
+  List<TypeExpr?> _cloneVariableValues(List<TypeExpr?> values) =>
+      new List<TypeExpr?>.from(values);
 
-  List<TypeExpr> _makeEmptyVariableValues() {
-    final values = new List<TypeExpr>.filled(_variablesInfo.numVariables, null);
+  List<TypeExpr?> _makeEmptyVariableValues() {
+    final values =
+        new List<TypeExpr?>.filled(_variablesInfo.numVariables, null);
     for (int i = 0; i < values.length; ++i) {
       if (_variableCells[i] != null) {
         values[i] = _variableValues[i];
@@ -978,11 +977,11 @@
     return join;
   }
 
-  void _mergeVariableValues(List<TypeExpr> dst, List<TypeExpr> src) {
+  void _mergeVariableValues(List<TypeExpr?> dst, List<TypeExpr?> src) {
     assert(dst.length == src.length);
     for (int i = 0; i < dst.length; ++i) {
-      final TypeExpr dstValue = dst[i];
-      final TypeExpr srcValue = src[i];
+      final TypeExpr? dstValue = dst[i];
+      final TypeExpr? srcValue = src[i];
       if (identical(dstValue, srcValue)) {
         continue;
       }
@@ -997,21 +996,21 @@
       } else if (srcValue is Join && srcValue.values.contains(dstValue)) {
         dst[i] = srcValue;
       } else {
-        final Join join = _makeJoin(i, dst[i]);
-        join.values.add(src[i]);
+        final Join join = _makeJoin(i, dstValue);
+        join.values.add(srcValue);
         dst[i] = join;
       }
     }
   }
 
-  void _copyVariableValues(List<TypeExpr> dst, List<TypeExpr> src) {
+  void _copyVariableValues(List<TypeExpr?> dst, List<TypeExpr?> src) {
     assert(dst.length == src.length);
     for (int i = 0; i < dst.length; ++i) {
       dst[i] = src[i];
     }
   }
 
-  bool _isIdenticalState(List<TypeExpr> state1, List<TypeExpr> state2) {
+  bool _isIdenticalState(List<TypeExpr?> state1, List<TypeExpr?> state2) {
     assert(state1.length == state2.length);
     for (int i = 0; i < state1.length; ++i) {
       if (!identical(state1[i], state2[i])) {
@@ -1021,14 +1020,14 @@
     return true;
   }
 
-  List<Join> _insertJoinsForModifiedVariables(TreeNode node, bool isTry) {
-    final List<Join> joins =
-        new List<Join>.filled(_variablesInfo.numVariables, null);
+  List<Join?> _insertJoinsForModifiedVariables(ast.Statement node, bool isTry) {
+    final List<Join?> joins =
+        new List<Join?>.filled(_variablesInfo.numVariables, null);
     for (var i in _variablesInfo.getModifiedVariables(node)) {
       if (_variableCells[i] != null) {
         assert(_variableCells[i] == _variableValues[i]);
       } else {
-        final join = _makeJoin(i, _variableValues[i]);
+        final join = _makeJoin(i, _variableValues[i]!);
         joins[i] = join;
         _variableValues[i] = join;
         if (isTry) {
@@ -1044,7 +1043,7 @@
 
   /// Stops accumulating values in [joins] by removing them from
   /// _variableCells.
-  void _restoreVariableCellsAfterTry(List<Join> joins) {
+  void _restoreVariableCellsAfterTry(List<Join?> joins) {
     for (int i = 0; i < joins.length; ++i) {
       if (joins[i] != null) {
         assert(_variableCells[i] == joins[i]);
@@ -1053,14 +1052,14 @@
     }
   }
 
-  void _mergeVariableValuesToJoins(List<TypeExpr> values, List<Join> joins) {
+  void _mergeVariableValuesToJoins(List<TypeExpr?> values, List<Join?> joins) {
     for (int i = 0; i < joins.length; ++i) {
       final join = joins[i];
       final value = values[i];
       if (join != null &&
           !identical(join, value) &&
           !identical(join.values.first, value)) {
-        join.values.add(value);
+        join.values.add(value!);
       }
     }
   }
@@ -1079,16 +1078,17 @@
 
   // TODO(alexmarkov): Avoid declaring variables with static types.
   void _declareVariableWithStaticType(VariableDeclaration decl) {
-    if (decl.initializer != null) {
-      _visit(decl.initializer);
+    final initializer = decl.initializer;
+    if (initializer != null) {
+      _visit(initializer);
     }
     _declareVariable(decl, _typesBuilder.fromStaticType(decl.type, true));
   }
 
   Call _makeCall(TreeNode node, Selector selector, Args<TypeExpr> args,
       {bool isInstanceCreation = false}) {
-    Type staticResultType = null;
-    Member target;
+    Type? staticResultType = null;
+    Member? target;
     if (selector is DirectSelector) {
       target = selector.member;
     } else if (selector is InterfaceSelector) {
@@ -1101,9 +1101,7 @@
     }
     Call call = new Call(selector, args, staticResultType, isInstanceCreation);
     _summary.add(call);
-    if (node != null) {
-      callSites[node] = call;
-    }
+    callSites[node] = call;
     return call;
   }
 
@@ -1189,53 +1187,43 @@
   }
 
   DartType _staticDartType(Expression node) =>
-      node.getStaticType(_staticTypeContext);
+      node.getStaticType(_staticTypeContext!);
 
   Type _staticType(Expression node) =>
       _typesBuilder.fromStaticType(_staticDartType(node), true);
 
-  ConcreteType _cachedBoolType;
-  ConcreteType get _boolType => _cachedBoolType ??=
+  late final ConcreteType _boolType =
       _entryPointsListener.addAllocatedClass(_environment.coreTypes.boolClass);
 
-  ConcreteType _cachedBoolTrue;
-  ConcreteType get _boolTrue => _cachedBoolTrue ??=
-      new ConcreteType(_boolType.cls, null, BoolConstant(true));
+  late final ConcreteType _boolTrue =
+      ConcreteType(_boolType.cls, null, BoolConstant(true));
 
-  ConcreteType _cachedBoolFalse;
-  ConcreteType get _boolFalse => _cachedBoolFalse ??=
-      new ConcreteType(_boolType.cls, null, BoolConstant(false));
+  late final ConcreteType _boolFalse =
+      ConcreteType(_boolType.cls, null, BoolConstant(false));
 
-  Type _cachedDoubleType;
-  Type get _doubleType => _cachedDoubleType ??= new ConeType(
-      _typesBuilder.getTFClass(_environment.coreTypes.doubleClass));
+  late final Type _doubleType =
+      ConeType(_typesBuilder.getTFClass(_environment.coreTypes.doubleClass));
 
-  Type _cachedIntType;
-  Type get _intType => _cachedIntType ??=
-      new ConeType(_typesBuilder.getTFClass(_environment.coreTypes.intClass));
+  late final Type _intType =
+      ConeType(_typesBuilder.getTFClass(_environment.coreTypes.intClass));
 
-  Type _cachedStringType;
-  Type get _stringType => _cachedStringType ??= new ConeType(
-      _typesBuilder.getTFClass(_environment.coreTypes.stringClass));
+  late final Type _stringType =
+      ConeType(_typesBuilder.getTFClass(_environment.coreTypes.stringClass));
 
-  Type _cachedSymbolType;
-  Type get _symbolType => _cachedSymbolType ??= new ConeType(
-      _typesBuilder.getTFClass(_environment.coreTypes.symbolClass));
+  late final Type _symbolType =
+      ConeType(_typesBuilder.getTFClass(_environment.coreTypes.symbolClass));
 
-  Type _cachedTypeType;
-  Type get _typeType => _cachedTypeType ??=
-      new ConeType(_typesBuilder.getTFClass(_environment.coreTypes.typeClass));
+  late final Type _typeType =
+      ConeType(_typesBuilder.getTFClass(_environment.coreTypes.typeClass));
 
-  Type _cachedNullType;
-  Type get _nullType =>
-      _cachedNullType ??= new Type.nullable(const EmptyType());
+  late final Type _nullType = Type.nullable(const EmptyType());
 
-  Class get _superclass => _staticTypeContext.thisType.classNode.superclass;
+  Class get _superclass => _staticTypeContext!.thisType!.classNode.superclass!;
 
   Type _boolLiteralType(bool value) => value ? _boolTrue : _boolFalse;
 
-  Type _intLiteralType(int value, Constant constant) {
-    final Class concreteClass =
+  Type _intLiteralType(int value, Constant? constant) {
+    final Class? concreteClass =
         target.concreteIntLiteralClass(_environment.coreTypes, value);
     if (concreteClass != null) {
       constant ??= IntConstant(value);
@@ -1247,8 +1235,8 @@
     return _intType;
   }
 
-  Type _doubleLiteralType(double value, Constant constant) {
-    final Class concreteClass =
+  Type _doubleLiteralType(double value, Constant? constant) {
+    final Class? concreteClass =
         target.concreteDoubleLiteralClass(_environment.coreTypes, value);
     if (concreteClass != null) {
       constant ??= DoubleConstant(value);
@@ -1260,8 +1248,8 @@
     return _doubleType;
   }
 
-  Type _stringLiteralType(String value, Constant constant) {
-    final Class concreteClass =
+  Type _stringLiteralType(String value, Constant? constant) {
+    final Class? concreteClass =
         target.concreteStringLiteralClass(_environment.coreTypes, value);
     if (concreteClass != null) {
       constant ??= StringConstant(value);
@@ -1284,7 +1272,7 @@
     node.positionalParameters.forEach(_declareVariableWithStaticType);
     node.namedParameters.forEach(_declareVariableWithStaticType);
 
-    _visit(node.body);
+    _visitWithoutResult(node.body!);
 
     _variableValues = savedVariableValues;
     _returnValue = savedReturn;
@@ -1307,8 +1295,7 @@
       for (Class c
           in _hierarchy.computeSubtypesInformation().getSubtypesOf(cls)) {
         if (!c.isAbstract) {
-          final candidate = _hierarchy.getDispatchTarget(c, _equalsName);
-          assert(candidate != null);
+          final candidate = _hierarchy.getDispatchTarget(c, _equalsName)!;
           assert(!candidate.isAbstract);
           if (candidate != _environment.coreTypes.objectEquals) {
             _cachedHasOverriddenEquals[cls] = true;
@@ -1328,12 +1315,12 @@
   // On exit _variableValues is null, so caller should explicitly pick
   // either trueState or falseState.
   void _visitCondition(
-      Expression node, List<TypeExpr> trueState, List<TypeExpr> falseState) {
+      Expression node, List<TypeExpr?> trueState, List<TypeExpr?> falseState) {
     assert(_isIdenticalState(_variableValues, trueState));
     assert(_isIdenticalState(_variableValues, falseState));
     if (node is Not) {
       _visitCondition(node.operand, falseState, trueState);
-      _variableValues = null;
+      _variableValues = const <TypeExpr?>[]; // Should not be used.
       return;
     } else if (node is LogicalExpression) {
       final isOR = (node.operatorEnum == LogicalExpressionOperator.OR);
@@ -1351,7 +1338,7 @@
         _visitCondition(node.right, trueState, falseStateAfterRHS);
         _mergeVariableValues(falseState, falseStateAfterRHS);
       }
-      _variableValues = null;
+      _variableValues = const <TypeExpr?>[]; // Should not be used.
       return;
     } else if (node is VariableGet ||
         (node is AsExpression && node.operand is VariableGet)) {
@@ -1359,12 +1346,12 @@
       _addUse(_visit(node));
       final variableGet =
           (node is AsExpression ? node.operand : node) as VariableGet;
-      final int varIndex = _variablesInfo.varIndex[variableGet.variable];
+      final int varIndex = _variablesInfo.varIndex[variableGet.variable]!;
       if (_variableCells[varIndex] == null) {
         trueState[varIndex] = _boolTrue;
         falseState[varIndex] = _boolFalse;
       }
-      _variableValues = null;
+      _variableValues = const <TypeExpr?>[]; // Should not be used.
       return;
     } else if (node is EqualsCall && node.left is VariableGet) {
       final lhs = node.left as VariableGet;
@@ -1379,11 +1366,11 @@
               !_hasOverriddenEquals(lhs.variable.type))) {
         // 'x == c', where x is a variable and c is a constant.
         _addUse(_visit(node));
-        final int varIndex = _variablesInfo.varIndex[lhs.variable];
+        final int varIndex = _variablesInfo.varIndex[lhs.variable]!;
         if (_variableCells[varIndex] == null) {
           trueState[varIndex] = _visit(rhs);
         }
-        _variableValues = null;
+        _variableValues = const <TypeExpr?>[]; // Should not be used.
         return;
       }
     } else if (node is EqualsNull && node.expression is VariableGet) {
@@ -1393,12 +1380,12 @@
       _makeCall(node, DirectSelector(_environment.coreTypes.objectEquals),
           Args<TypeExpr>([expr, _nullType]));
       final narrowedNotNull = _makeNarrowNotNull(node, expr);
-      final int varIndex = _variablesInfo.varIndex[lhs.variable];
+      final int varIndex = _variablesInfo.varIndex[lhs.variable]!;
       if (_variableCells[varIndex] == null) {
         trueState[varIndex] = _nullType;
         falseState[varIndex] = narrowedNotNull;
       }
-      _variableValues = null;
+      _variableValues = const <TypeExpr?>[]; // Should not be used.
       return;
     } else if (node is IsExpression && node.operand is VariableGet) {
       // Handle 'x is T', where x is a variable.
@@ -1406,17 +1393,17 @@
       final TypeCheck typeCheck =
           _typeCheck(_visit(operand), node.type, node, SubtypeTestKind.IsTest);
       isTests[node] = typeCheck;
-      final int varIndex = _variablesInfo.varIndex[operand.variable];
+      final int varIndex = _variablesInfo.varIndex[operand.variable]!;
       if (_variableCells[varIndex] == null) {
         trueState[varIndex] = typeCheck;
       }
-      _variableValues = null;
+      _variableValues = const <TypeExpr?>[]; // Should not be used.
       return;
     }
     _addUse(_visit(node));
     _copyVariableValues(trueState, _variableValues);
     _copyVariableValues(falseState, _variableValues);
-    _variableValues = null;
+    _variableValues = const <TypeExpr?>[]; // Should not be used.
   }
 
   void _updateReceiverAfterCall(
@@ -1425,7 +1412,7 @@
     if (receiverNode is VariableGet) {
       final nullSelectors = isSetter ? _nullSetters : _nullMethodsAndGetters;
       if (!nullSelectors.contains(selector)) {
-        final int varIndex = _variablesInfo.varIndex[receiverNode.variable];
+        final int varIndex = _variablesInfo.varIndex[receiverNode.variable]!;
         if (_variableCells[varIndex] == null) {
           _variableValues[varIndex] =
               _makeNarrow(receiverValue, const AnyType());
@@ -1434,9 +1421,8 @@
     }
   }
 
-  Procedure _cachedUnsafeCast;
-  Procedure get unsafeCast => _cachedUnsafeCast ??= _environment.coreTypes.index
-      .getTopLevelMember('dart:_internal', 'unsafeCast');
+  late final Procedure unsafeCast = _environment.coreTypes.index
+      .getTopLevelProcedure('dart:_internal', 'unsafeCast');
 
   @override
   defaultTreeNode(TreeNode node) =>
@@ -1446,10 +1432,10 @@
   TypeExpr visitAsExpression(AsExpression node) {
     final operandNode = node.operand;
     final TypeExpr operand = _visit(operandNode);
-    final TypeExpr result = _typeCheck(operand, node.type, node);
+    final TypeCheck result = _typeCheck(operand, node.type, node);
     explicitCasts[node] = result;
     if (operandNode is VariableGet) {
-      final int varIndex = _variablesInfo.varIndex[operandNode.variable];
+      final int varIndex = _variablesInfo.varIndex[operandNode.variable]!;
       if (_variableCells[varIndex] == null) {
         _variableValues[varIndex] = result;
       }
@@ -1462,7 +1448,7 @@
     final operandNode = node.operand;
     final TypeExpr result = _makeNarrowNotNull(node, _visit(operandNode));
     if (operandNode is VariableGet) {
-      final int varIndex = _variablesInfo.varIndex[operandNode.variable];
+      final int varIndex = _variablesInfo.varIndex[operandNode.variable]!;
       if (_variableCells[varIndex] == null) {
         _variableValues[varIndex] = result;
       }
@@ -1549,20 +1535,20 @@
 
   @override
   TypeExpr visitLet(Let node) {
-    _declareVariable(node.variable, _visit(node.variable.initializer));
+    _declareVariable(node.variable, _visit(node.variable.initializer!));
     return _visit(node.body);
   }
 
   @override
   TypeExpr visitBlockExpression(BlockExpression node) {
-    _visit(node.body);
+    _visitWithoutResult(node.body);
     return _visit(node.value);
   }
 
   @override
   TypeExpr visitListLiteral(ListLiteral node) {
     node.expressions.forEach(_visit);
-    Class concreteClass =
+    Class? concreteClass =
         target.concreteListLiteralClass(_environment.coreTypes);
     if (concreteClass != null) {
       return _translator.instantiateConcreteType(
@@ -1588,7 +1574,7 @@
       _visit(entry.key);
       _visit(entry.value);
     }
-    Class concreteClass =
+    Class? concreteClass =
         target.concreteMapLiteralClass(_environment.coreTypes);
     if (concreteClass != null) {
       return _translator.instantiateConcreteType(
@@ -1690,7 +1676,7 @@
   }
 
   TypeExpr _handlePropertyGet(
-      TreeNode node, Expression receiverNode, Member target, Name selector) {
+      TreeNode node, Expression receiverNode, Member? target, Name selector) {
     var receiver = _visit(receiverNode);
     var args = new Args<TypeExpr>([receiver]);
     TypeExpr result;
@@ -1779,8 +1765,7 @@
   @override
   TypeExpr visitSuperPropertyGet(SuperPropertyGet node) {
     assert(kPartialMixinResolution);
-    assert(_receiver != null, "Should have receiver. Node: $node");
-    final args = new Args<TypeExpr>([_receiver]);
+    final args = new Args<TypeExpr>([_receiver!]);
     // Re-resolve target due to partial mixin resolution.
     final target = _hierarchy.getDispatchTarget(_superclass, node.name);
     if (target == null) {
@@ -1794,9 +1779,8 @@
   @override
   TypeExpr visitSuperPropertySet(SuperPropertySet node) {
     assert(kPartialMixinResolution);
-    assert(_receiver != null, "Should have receiver. Node: $node");
     final value = _visit(node.value);
-    final args = new Args<TypeExpr>([_receiver, value]);
+    final args = new Args<TypeExpr>([_receiver!, value]);
     // Re-resolve target due to partial mixin resolution.
     final target =
         _hierarchy.getDispatchTarget(_superclass, node.name, setter: true);
@@ -1882,8 +1866,7 @@
 
   @override
   TypeExpr visitThisExpression(ThisExpression node) {
-    assert(_receiver != null, "Should have receiver. Node: $node");
-    return _receiver;
+    return _receiver!;
   }
 
   @override
@@ -1900,7 +1883,7 @@
 
   @override
   TypeExpr visitVariableGet(VariableGet node) {
-    final v = _variableValues[_variablesInfo.varIndex[node.variable]];
+    final v = _variableValues[_variablesInfo.varIndex[node.variable]!];
     if (v == null) {
       throw 'Unable to find variable ${node.variable} at ${node.location}';
     }
@@ -1925,56 +1908,60 @@
   }
 
   @override
-  TypeExpr visitAssertStatement(AssertStatement node) {
+  TypeExpr? visitAssertStatement(AssertStatement node) {
     if (!kRemoveAsserts) {
       _addUse(_visit(node.condition));
-      if (node.message != null) {
-        _visit(node.message);
+      final message = node.message;
+      if (message != null) {
+        _visit(message);
       }
     }
     return null;
   }
 
   @override
-  TypeExpr visitBlock(Block node) {
-    node.statements.forEach(_visit);
+  TypeExpr? visitBlock(Block node) {
+    node.statements.forEach(_visitWithoutResult);
     return null;
   }
 
   @override
-  TypeExpr visitAssertBlock(AssertBlock node) {
+  TypeExpr? visitAssertBlock(AssertBlock node) {
     if (!kRemoveAsserts) {
-      node.statements.forEach(_visit);
+      node.statements.forEach(_visitWithoutResult);
     }
     return null;
   }
 
   @override
-  TypeExpr visitBreakStatement(BreakStatement node) {
-    _variableValuesAfterLabeledStatements ??=
-        <LabeledStatement, List<TypeExpr>>{};
-    final state = _variableValuesAfterLabeledStatements[node.target];
+  TypeExpr? visitBreakStatement(BreakStatement node) {
+    var afterLabels = _variableValuesAfterLabeledStatements;
+    if (afterLabels == null) {
+      _variableValuesAfterLabeledStatements =
+          afterLabels = <LabeledStatement, List<TypeExpr?>>{};
+    }
+    final state = afterLabels[node.target];
     if (state != null) {
       _mergeVariableValues(state, _variableValues);
     } else {
-      _variableValuesAfterLabeledStatements[node.target] = _variableValues;
+      afterLabels[node.target] = _variableValues;
     }
     _variableValues = _makeEmptyVariableValues();
     return null;
   }
 
   @override
-  TypeExpr visitContinueSwitchStatement(ContinueSwitchStatement node) {
+  TypeExpr? visitContinueSwitchStatement(ContinueSwitchStatement node) {
     _mergeVariableValuesToJoins(
-        _variableValues, _joinsAtSwitchCases[node.target]);
+        _variableValues, _joinsAtSwitchCases![node.target]!);
     _variableValues = _makeEmptyVariableValues();
     return null;
   }
 
   @override
-  TypeExpr visitDoStatement(DoStatement node) {
-    final List<Join> joins = _insertJoinsForModifiedVariables(node, false);
-    _visit(node.body);
+  TypeExpr? visitDoStatement(DoStatement node) {
+    final List<Join?> joins = _insertJoinsForModifiedVariables(node, false);
+    _visitWithoutResult(node.body);
     final trueState = _cloneVariableValues(_variableValues);
     final falseState = _cloneVariableValues(_variableValues);
     _visitCondition(node.condition, trueState, falseState);
@@ -1988,39 +1975,39 @@
   }
 
   @override
-  TypeExpr visitEmptyStatement(EmptyStatement node) => null;
+  TypeExpr? visitEmptyStatement(EmptyStatement node) => null;
 
   @override
-  TypeExpr visitExpressionStatement(ExpressionStatement node) {
+  TypeExpr? visitExpressionStatement(ExpressionStatement node) {
     _visit(node.expression);
     return null;
   }
 
   @override
-  TypeExpr visitForInStatement(ForInStatement node) {
+  TypeExpr? visitForInStatement(ForInStatement node) {
     _visit(node.iterable);
     // TODO(alexmarkov): try to infer more precise type from 'iterable'
     _declareVariableWithStaticType(node.variable);
 
-    final List<Join> joins = _insertJoinsForModifiedVariables(node, false);
+    final List<Join?> joins = _insertJoinsForModifiedVariables(node, false);
     final stateAfterLoop = _cloneVariableValues(_variableValues);
-    _visit(node.body);
+    _visitWithoutResult(node.body);
     _mergeVariableValuesToJoins(_variableValues, joins);
     _variableValues = stateAfterLoop;
     return null;
   }
 
   @override
-  TypeExpr visitForStatement(ForStatement node) {
+  TypeExpr? visitForStatement(ForStatement node) {
     node.variables.forEach(visitVariableDeclaration);
-    final List<Join> joins = _insertJoinsForModifiedVariables(node, false);
+    final List<Join?> joins = _insertJoinsForModifiedVariables(node, false);
     final trueState = _cloneVariableValues(_variableValues);
     final falseState = _cloneVariableValues(_variableValues);
     if (node.condition != null) {
-      _visitCondition(node.condition, trueState, falseState);
+      _visitCondition(node.condition!, trueState, falseState);
     }
     _variableValues = trueState;
-    _visit(node.body);
+    _visitWithoutResult(node.body);
     node.updates.forEach(_visit);
     _mergeVariableValuesToJoins(_variableValues, joins);
     // Kernel represents 'break;' as a BreakStatement referring to a
@@ -2032,7 +2019,7 @@
   }
 
   @override
-  TypeExpr visitFunctionDeclaration(FunctionDeclaration node) {
+  TypeExpr? visitFunctionDeclaration(FunctionDeclaration node) {
     // TODO(alexmarkov): support function types.
     node.variable.annotations.forEach(_visit);
     _declareVariableWithStaticType(node.variable);
@@ -2041,18 +2028,18 @@
   }
 
   @override
-  TypeExpr visitIfStatement(IfStatement node) {
+  TypeExpr? visitIfStatement(IfStatement node) {
     final trueState = _cloneVariableValues(_variableValues);
     final falseState = _cloneVariableValues(_variableValues);
     _visitCondition(node.condition, trueState, falseState);
 
     _variableValues = trueState;
-    _visit(node.then);
+    _visitWithoutResult(node.then);
     final stateAfter = _variableValues;
 
     _variableValues = falseState;
     if (node.otherwise != null) {
-      _visit(node.otherwise);
+      _visitWithoutResult(node.otherwise!);
     }
 
     _mergeVariableValues(stateAfter, _variableValues);
@@ -2061,8 +2048,8 @@
   }
 
   @override
-  TypeExpr visitLabeledStatement(LabeledStatement node) {
-    _visit(node.body);
+  TypeExpr? visitLabeledStatement(LabeledStatement node) {
+    _visitWithoutResult(node.body);
     final state = _variableValuesAfterLabeledStatements?.remove(node);
     if (state != null) {
       _mergeVariableValues(_variableValues, state);
@@ -2071,34 +2058,35 @@
   }
 
   @override
-  TypeExpr visitReturnStatement(ReturnStatement node) {
-    TypeExpr ret =
-        (node.expression != null) ? _visit(node.expression) : _nullType;
-    if (_returnValue != null) {
-      _returnValue.values.add(ret);
-    }
+  TypeExpr? visitReturnStatement(ReturnStatement node) {
+    final expression = node.expression;
+    TypeExpr ret = (expression != null) ? _visit(expression) : _nullType;
+    _returnValue?.values.add(ret);
     _variableValues = _makeEmptyVariableValues();
     return null;
   }
 
   @override
-  TypeExpr visitSwitchStatement(SwitchStatement node) {
+  TypeExpr? visitSwitchStatement(SwitchStatement node) {
     _visit(node.expression);
     // Insert joins at each case in case there are 'continue' statements.
     final stateOnEntry = _variableValues;
-    final variableValuesAtCaseEntry = <SwitchCase, List<TypeExpr>>{};
-    _joinsAtSwitchCases ??= <SwitchCase, List<Join>>{};
+    final variableValuesAtCaseEntry = <SwitchCase, List<TypeExpr?>>{};
+    Map<SwitchCase, List<Join?>>? joinsAtSwitchCases = _joinsAtSwitchCases;
+    if (joinsAtSwitchCases == null) {
+      _joinsAtSwitchCases = joinsAtSwitchCases = <SwitchCase, List<Join?>>{};
+    }
     for (var switchCase in node.cases) {
       _variableValues = _cloneVariableValues(stateOnEntry);
-      _joinsAtSwitchCases[switchCase] =
+      joinsAtSwitchCases[switchCase] =
           _insertJoinsForModifiedVariables(node, false);
       variableValuesAtCaseEntry[switchCase] = _variableValues;
     }
     bool hasDefault = false;
     for (var switchCase in node.cases) {
-      _variableValues = variableValuesAtCaseEntry[switchCase];
+      _variableValues = variableValuesAtCaseEntry[switchCase]!;
       switchCase.expressions.forEach(_visit);
-      _visit(switchCase.body);
+      _visitWithoutResult(switchCase.body);
       hasDefault = hasDefault || switchCase.isDefault;
     }
     if (!hasDefault) {
@@ -2108,21 +2096,21 @@
   }
 
   @override
-  TypeExpr visitTryCatch(TryCatch node) {
+  TypeExpr? visitTryCatch(TryCatch node) {
     final joins = _insertJoinsForModifiedVariables(node, true);
     final stateAfterTry = _cloneVariableValues(_variableValues);
-    _visit(node.body);
+    _visitWithoutResult(node.body);
     _restoreVariableCellsAfterTry(joins);
-    List<TypeExpr> stateAfterCatch;
+    List<TypeExpr?>? stateAfterCatch;
     for (var catchClause in node.catches) {
       _variableValues = _cloneVariableValues(stateAfterTry);
       if (catchClause.exception != null) {
-        _declareVariableWithStaticType(catchClause.exception);
+        _declareVariableWithStaticType(catchClause.exception!);
       }
       if (catchClause.stackTrace != null) {
-        _declareVariableWithStaticType(catchClause.stackTrace);
+        _declareVariableWithStaticType(catchClause.stackTrace!);
       }
-      _visit(catchClause.body);
+      _visitWithoutResult(catchClause.body);
       if (stateAfterCatch == null) {
         stateAfterCatch = _variableValues;
       } else {
@@ -2130,38 +2118,39 @@
       }
     }
     _variableValues = stateAfterTry;
-    _mergeVariableValues(_variableValues, stateAfterCatch);
+    _mergeVariableValues(_variableValues, stateAfterCatch!);
     return null;
   }
 
   @override
-  TypeExpr visitTryFinally(TryFinally node) {
+  TypeExpr? visitTryFinally(TryFinally node) {
     final joins = _insertJoinsForModifiedVariables(node, true);
     final stateAfterTry = _cloneVariableValues(_variableValues);
-    _visit(node.body);
+    _visitWithoutResult(node.body);
     _restoreVariableCellsAfterTry(joins);
     _variableValues = stateAfterTry;
-    _visit(node.finalizer);
+    _visitWithoutResult(node.finalizer);
     return null;
   }
 
   @override
-  TypeExpr visitVariableDeclaration(VariableDeclaration node) {
+  TypeExpr? visitVariableDeclaration(VariableDeclaration node) {
     node.annotations.forEach(_visit);
+    final initializer = node.initializer;
     final TypeExpr initialValue =
-        node.initializer == null ? _nullType : _visit(node.initializer);
+        initializer == null ? _nullType : _visit(initializer);
     _declareVariable(node, initialValue);
     return null;
   }
 
   @override
-  TypeExpr visitWhileStatement(WhileStatement node) {
-    final List<Join> joins = _insertJoinsForModifiedVariables(node, false);
+  TypeExpr? visitWhileStatement(WhileStatement node) {
+    final List<Join?> joins = _insertJoinsForModifiedVariables(node, false);
     final trueState = _cloneVariableValues(_variableValues);
     final falseState = _cloneVariableValues(_variableValues);
     _visitCondition(node.condition, trueState, falseState);
     _variableValues = trueState;
-    _visit(node.body);
+    _visitWithoutResult(node.body);
     _mergeVariableValuesToJoins(_variableValues, joins);
     // Kernel represents 'break;' as a BreakStatement referring to a
     // LabeledStatement. We are therefore guaranteed to always have the
@@ -2172,15 +2161,15 @@
   }
 
   @override
-  TypeExpr visitYieldStatement(YieldStatement node) {
+  TypeExpr? visitYieldStatement(YieldStatement node) {
     _visit(node.expression);
     return null;
   }
 
   @override
-  TypeExpr visitFieldInitializer(FieldInitializer node) {
+  TypeExpr? visitFieldInitializer(FieldInitializer node) {
     final value = _visit(node.value);
-    final args = new Args<TypeExpr>([_receiver, value]);
+    final args = new Args<TypeExpr>([_receiver!, value]);
     _makeCall(
         node,
         new DirectSelector(node.field,
@@ -2190,17 +2179,17 @@
   }
 
   @override
-  TypeExpr visitRedirectingInitializer(RedirectingInitializer node) {
+  TypeExpr? visitRedirectingInitializer(RedirectingInitializer node) {
     final args = _visitArguments(_receiver, node.arguments);
     _makeCall(node, new DirectSelector(node.target), args);
     return null;
   }
 
   @override
-  TypeExpr visitSuperInitializer(SuperInitializer node) {
+  TypeExpr? visitSuperInitializer(SuperInitializer node) {
     final args = _visitArguments(_receiver, node.arguments);
 
-    Constructor target = null;
+    Constructor? target = null;
     if (kPartialMixinResolution) {
       // Re-resolve target due to partial mixin resolution.
       for (var replacement in _superclass.constructors) {
@@ -2212,27 +2201,26 @@
     } else {
       target = node.target;
     }
-    assert(target != null);
-    _makeCall(node, new DirectSelector(target), args);
+    _makeCall(node, new DirectSelector(target!), args);
     return null;
   }
 
   @override
-  TypeExpr visitLocalInitializer(LocalInitializer node) {
+  TypeExpr? visitLocalInitializer(LocalInitializer node) {
     visitVariableDeclaration(node.variable);
     return null;
   }
 
   @override
-  TypeExpr visitAssertInitializer(AssertInitializer node) {
+  TypeExpr? visitAssertInitializer(AssertInitializer node) {
     if (!kRemoveAsserts) {
-      _visit(node.statement);
+      _visitWithoutResult(node.statement);
     }
     return null;
   }
 
   @override
-  TypeExpr visitInvalidInitializer(InvalidInitializer node) {
+  TypeExpr? visitInvalidInitializer(InvalidInitializer node) {
     return null;
   }
 
@@ -2244,21 +2232,21 @@
 
 class RuntimeTypeTranslatorImpl extends DartTypeVisitor<TypeExpr>
     implements RuntimeTypeTranslator {
-  final Summary summary;
-  final Map<TypeParameter, TypeExpr> functionTypeVariables;
+  final CoreTypes coreTypes;
+  final Summary? summary;
+  final Map<TypeParameter, TypeExpr>? functionTypeVariables;
   final Map<DartType, TypeExpr> typesCache = <DartType, TypeExpr>{};
-  final TypeExpr receiver;
+  final TypeExpr? receiver;
   final GenericInterfacesInfo genericInterfacesInfo;
-  final SummaryCollector summaryCollector;
 
-  RuntimeTypeTranslatorImpl(this.summaryCollector, this.summary, this.receiver,
+  RuntimeTypeTranslatorImpl(this.coreTypes, this.summary, this.receiver,
       this.functionTypeVariables, this.genericInterfacesInfo) {}
 
   // Create a type translator which can be used only for types with no free type
   // variables.
-  RuntimeTypeTranslatorImpl.forClosedTypes(this.genericInterfacesInfo)
-      : summaryCollector = null,
-        summary = null,
+  RuntimeTypeTranslatorImpl.forClosedTypes(
+      this.coreTypes, this.genericInterfacesInfo)
+      : summary = null,
         functionTypeVariables = null,
         receiver = null {}
 
@@ -2271,8 +2259,7 @@
     final substitution = Substitution.fromPairs(klass.typeParameters, typeArgs);
     final flattenedTypeArgs =
         genericInterfacesInfo.flattenedTypeArgumentsFor(klass);
-    final flattenedTypeExprs =
-        new List<TypeExpr>.filled(flattenedTypeArgs.length, null);
+    final flattenedTypeExprs = <TypeExpr>[];
 
     bool createConcreteType = true;
     bool allUnknown = true;
@@ -2281,7 +2268,7 @@
           translate(substitution.substituteType(flattenedTypeArgs[i]));
       if (typeExpr is! UnknownType) allUnknown = false;
       if (typeExpr is Statement) createConcreteType = false;
-      flattenedTypeExprs[i] = typeExpr;
+      flattenedTypeExprs.add(typeExpr);
     }
 
     if (allUnknown) return type;
@@ -2291,7 +2278,7 @@
           type.cls, new List<Type>.from(flattenedTypeExprs));
     } else {
       final instantiate = new CreateConcreteType(type.cls, flattenedTypeExprs);
-      summary.add(instantiate);
+      summary!.add(instantiate);
       return instantiate;
     }
   }
@@ -2341,8 +2328,7 @@
         type.classNode.typeParameters, type.typeArguments);
     final flattenedTypeArgs =
         genericInterfacesInfo.flattenedTypeArgumentsFor(type.classNode);
-    final flattenedTypeExprs =
-        new List<TypeExpr>.filled(flattenedTypeArgs.length, null);
+    final flattenedTypeExprs = <TypeExpr>[];
 
     bool createRuntimeType = true;
     for (var i = 0; i < flattenedTypeArgs.length; ++i) {
@@ -2350,7 +2336,7 @@
           translate(substitution.substituteType(flattenedTypeArgs[i]));
       if (typeExpr == const UnknownType()) return const UnknownType();
       if (typeExpr is! RuntimeType) createRuntimeType = false;
-      flattenedTypeExprs[i] = typeExpr;
+      flattenedTypeExprs.add(typeExpr);
     }
 
     if (createRuntimeType) {
@@ -2360,7 +2346,7 @@
     } else {
       final instantiate = new CreateRuntimeType(
           type.classNode, type.nullability, flattenedTypeExprs);
-      summary.add(instantiate);
+      summary!.add(instantiate);
       return instantiate;
     }
   }
@@ -2375,32 +2361,32 @@
           <RuntimeType>[typeArg]);
     } else {
       final instantiate = new CreateRuntimeType(
-          summaryCollector._environment.coreTypes.deprecatedFutureOrClass,
+          coreTypes.deprecatedFutureOrClass,
           type.nullability,
           <TypeExpr>[typeArg]);
-      summary.add(instantiate);
+      summary!.add(instantiate);
       return instantiate;
     }
   }
 
   @override
   visitTypeParameterType(TypeParameterType type) {
+    final functionTypeVariables = this.functionTypeVariables;
     if (functionTypeVariables != null) {
       final result = functionTypeVariables[type.parameter];
       if (result != null) return result;
     }
     if (type.parameter.parent is! Class) return const UnknownType();
     final interfaceClass = type.parameter.parent as Class;
-    assert(receiver != null);
     // Undetermined nullability is equivalent to nonNullable when
     // instantiating type parameter, so convert it right away.
     Nullability nullability = type.nullability;
     if (nullability == Nullability.undetermined) {
       nullability = Nullability.nonNullable;
     }
-    final extract = new Extract(receiver, interfaceClass,
+    final extract = new Extract(receiver!, interfaceClass,
         interfaceClass.typeParameters.indexOf(type.parameter), nullability);
-    summary.add(extract);
+    summary!.add(extract);
     return extract;
   }
 }
@@ -2420,7 +2406,7 @@
 
   Type _getStaticType(Constant constant) =>
       summaryCollector._typesBuilder.fromStaticType(
-          constant.getType(summaryCollector._staticTypeContext), false);
+          constant.getType(summaryCollector._staticTypeContext!), false);
 
   @override
   defaultConstant(Constant constant) {
@@ -2467,7 +2453,7 @@
     for (final Constant entry in constant.entries) {
       typeFor(entry);
     }
-    final Class concreteClass = summaryCollector.target
+    final Class? concreteClass = summaryCollector.target
         .concreteConstListLiteralClass(summaryCollector._environment.coreTypes);
     if (concreteClass != null) {
       return new ConcreteType(
diff --git a/pkg/vm/lib/transformations/type_flow/table_selector_assigner.dart b/pkg/vm/lib/transformations/type_flow/table_selector_assigner.dart
index f1901e7..0080748 100644
--- a/pkg/vm/lib/transformations/type_flow/table_selector_assigner.dart
+++ b/pkg/vm/lib/transformations/type_flow/table_selector_assigner.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
-
 import 'package:kernel/ast.dart';
 
 import 'utils.dart' show UnionFind;
@@ -18,7 +16,7 @@
   final Map<Class, Map<Name, int>> _methodOrSetterMemberIds = {};
 
   final UnionFind _unionFind = UnionFind();
-  List<int> _selectorIdForMemberId;
+  late List<int?> _selectorIdForMemberId;
 
   TableSelectorAssigner(Component component) {
     for (Library library in component.libraries) {
@@ -44,20 +42,21 @@
     }
   }
 
-  Map<Name, int> _memberIdsForClass(Class cls, {bool getter}) {
+  Map<Name, int> _memberIdsForClass(Class? cls, {required bool getter}) {
     if (cls == null) return {};
 
     final cache = getter ? _getterMemberIds : _methodOrSetterMemberIds;
 
     // Already computed for this class?
-    Map<Name, int> memberIds = cache[cls];
-    if (memberIds != null) return memberIds;
+    final cachedMemberIds = cache[cls];
+    if (cachedMemberIds != null) return cachedMemberIds;
 
     // Merge maps from supertypes.
-    memberIds = Map.from(_memberIdsForClass(cls.superclass, getter: getter));
+    final memberIds =
+        Map<Name, int>.from(_memberIdsForClass(cls.superclass, getter: getter));
     for (Supertype impl in cls.implementedTypes) {
       _memberIdsForClass(impl.classNode, getter: getter).forEach((name, id) {
-        final int firstId = memberIds[name];
+        final int? firstId = memberIds[name];
         if (firstId == null) {
           memberIds[name] = id;
         } else if (firstId != id) {
@@ -99,9 +98,9 @@
     return cache[cls] = memberIds;
   }
 
-  int _selectorIdForMember(Member member, {bool getter}) {
+  int _selectorIdForMember(Member member, {required bool getter}) {
     final map = getter ? _getterMemberIds : _methodOrSetterMemberIds;
-    int memberId = map[member.enclosingClass][member.name];
+    int? memberId = map[member.enclosingClass!]![member.name];
     if (memberId == null) {
       assert(member is Procedure &&
               ((identical(map, _getterMemberIds) &&
@@ -115,7 +114,7 @@
       return ProcedureAttributesMetadata.kInvalidSelectorId;
     }
     memberId = _unionFind.find(memberId);
-    int selectorId = _selectorIdForMemberId[memberId];
+    int? selectorId = _selectorIdForMemberId[memberId];
     if (selectorId == null) {
       _selectorIdForMemberId[memberId] = selectorId = metadata.addSelector();
     }
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index feb185d..82bebec 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -2,10 +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 file.
 
-// @dart=2.9
-
 /// Transformations based on type flow analysis.
-library vm.transformations.type_flow.transformer;
 
 import 'dart:core' hide Type;
 
@@ -14,7 +11,8 @@
 import 'package:kernel/ast.dart' as ast show Statement;
 import 'package:kernel/clone.dart' show CloneVisitorNotMembers;
 import 'package:kernel/core_types.dart' show CoreTypes;
-import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
+import 'package:kernel/class_hierarchy.dart'
+    show ClassHierarchy, ClosedWorldClassHierarchy;
 import 'package:kernel/library_index.dart' show LibraryIndex;
 import 'package:kernel/type_environment.dart';
 
@@ -43,16 +41,18 @@
 /// Assumes strong mode and closed world.
 Component transformComponent(
     Target target, CoreTypes coreTypes, Component component,
-    {PragmaAnnotationParser matcher,
+    {PragmaAnnotationParser? matcher,
     bool treeShakeSignatures: true,
     bool treeShakeWriteOnlyFields: true,
     bool treeShakeProtobufs: false}) {
   void ignoreAmbiguousSupertypes(Class cls, Supertype a, Supertype b) {}
   final hierarchy = new ClassHierarchy(component, coreTypes,
-      onAmbiguousSupertypes: ignoreAmbiguousSupertypes);
+          onAmbiguousSupertypes: ignoreAmbiguousSupertypes)
+      as ClosedWorldClassHierarchy;
   final types = new TypeEnvironment(coreTypes, hierarchy);
   final libraryIndex = new LibraryIndex.all(component);
-  final genericInterfacesInfo = new GenericInterfacesInfoImpl(hierarchy);
+  final genericInterfacesInfo =
+      new GenericInterfacesInfoImpl(coreTypes, hierarchy);
   final protobufHandler = treeShakeProtobufs
       ? ProtobufHandler.forComponent(component, coreTypes)
       : null;
@@ -73,7 +73,7 @@
       protobufHandler,
       matcher);
 
-  Procedure main = component.mainMethod;
+  Procedure? main = component.mainMethod;
 
   // `main` can be null, roots can also come from @pragma("vm:entry-point").
   if (main != null) {
@@ -149,7 +149,7 @@
         if (!f.isStatic &&
             !f.isLate &&
             f.initializer != null &&
-            mayHaveSideEffects(f.initializer))
+            mayHaveSideEffects(f.initializer!))
           f
     ];
     if (fields.isEmpty) return;
@@ -173,7 +173,7 @@
       };
       final List<Initializer> newInitializers = [];
       for (Field f in fields) {
-        Expression initExpr = f.initializer;
+        Expression initExpr = f.initializer!;
         if (!isFirst) {
           initExpr = CloneVisitorNotMembers().clone(initExpr);
         }
@@ -204,7 +204,7 @@
 class CleanupAnnotations extends RecursiveVisitor {
   final Class externalNameClass;
   final Class pragmaClass;
-  final ProtobufHandler protobufHandler;
+  final ProtobufHandler? protobufHandler;
 
   CleanupAnnotations(
       CoreTypes coreTypes, LibraryIndex index, this.protobufHandler)
@@ -238,7 +238,7 @@
         return (cls == externalNameClass) ||
             (cls == pragmaClass) ||
             (protobufHandler != null &&
-                protobufHandler.usesAnnotationClass(cls));
+                protobufHandler!.usesAnnotationClass(cls));
       }
     }
     return false;
@@ -255,11 +255,11 @@
       : super(_typeFlowAnalysis.environment.coreTypes, component, hierarchy);
 
   @override
-  DirectCallMetadata getDirectCall(TreeNode node, Member interfaceTarget,
+  DirectCallMetadata? getDirectCall(TreeNode node, Member? interfaceTarget,
       {bool setter = false}) {
     final callSite = _typeFlowAnalysis.callSite(node);
     if (callSite != null) {
-      final Member singleTarget = fieldMorpher
+      final Member? singleTarget = fieldMorpher
           .getMorphedMember(callSite.monomorphicTarget, isSetter: setter);
       if (singleTarget != null) {
         return new DirectCallMetadata(
@@ -283,12 +283,13 @@
   final UnboxingInfoMetadataRepository _unboxingInfoMetadata;
   final UnboxingInfoManager _unboxingInfo;
   final Class _intClass;
-  Constant _nullConstant;
+  late final Constant _nullConstant = NullConstant();
 
   AnnotateKernel(Component component, this._typeFlowAnalysis, this.fieldMorpher,
       this._tableSelectorAssigner, this._unboxingInfo)
       : _directCallMetadataRepository =
-            component.metadata[DirectCallMetadataRepository.repositoryTag],
+            component.metadata[DirectCallMetadataRepository.repositoryTag]
+                as DirectCallMetadataRepository,
         _inferredTypeMetadata = new InferredTypeMetadataRepository(),
         _unreachableNodeMetadata = new UnreachableNodeMetadataRepository(),
         _procedureAttributesMetadata =
@@ -308,12 +309,10 @@
     return _directCallMetadataRepository.mapping.containsKey(node);
   }
 
-  InferredType _convertType(Type type,
+  InferredType? _convertType(Type type,
       {bool skipCheck: false, bool receiverNotInt: false}) {
-    assert(type != null);
-
-    Class concreteClass;
-    Constant constantValue;
+    Class? concreteClass;
+    Constant? constantValue;
     bool isInt = false;
 
     final nullable = type is NullableType;
@@ -324,7 +323,7 @@
     if (nullable && type == const EmptyType()) {
       concreteClass =
           _typeFlowAnalysis.environment.coreTypes.deprecatedNullClass;
-      constantValue = _nullConstant ??= new NullConstant();
+      constantValue = _nullConstant;
     } else {
       concreteClass = type.getConcreteClass(_typeFlowAnalysis.hierarchyCache);
 
@@ -337,9 +336,9 @@
       }
     }
 
-    List<DartType> typeArgs;
+    List<DartType?>? typeArgs;
     if (type is ConcreteType && type.typeArgs != null) {
-      typeArgs = type.typeArgs
+      typeArgs = type.typeArgs!
           .take(type.numImmediateTypeArgs)
           .map((t) =>
               t is UnknownType ? null : (t as RuntimeType).representedType)
@@ -374,7 +373,7 @@
     _unreachableNodeMetadata.mapping[node] = const UnreachableNode();
   }
 
-  void _annotateCallSite(TreeNode node, Member interfaceTarget) {
+  void _annotateCallSite(TreeNode node, Member? interfaceTarget) {
     final callSite = _typeFlowAnalysis.callSite(node);
     if (callSite == null) return;
     if (!callSite.isReachable) {
@@ -405,7 +404,7 @@
         if (interfaceTarget == null ||
             _typeFlowAnalysis.hierarchyCache.hierarchy.isSubtypeOf(
                 _typeFlowAnalysis.hierarchyCache.coreTypes.intClass,
-                interfaceTarget.enclosingClass)) {
+                interfaceTarget.enclosingClass!)) {
           markReceiverNotInt = true;
         }
       }
@@ -446,35 +445,33 @@
   void _annotateMember(Member member) {
     if (_typeFlowAnalysis.isMemberUsed(member)) {
       if (member is Field) {
-        _setInferredType(member, _typeFlowAnalysis.fieldType(member));
+        _setInferredType(member, _typeFlowAnalysis.fieldType(member)!);
       } else {
-        Args<Type> argTypes = _typeFlowAnalysis.argumentTypes(member);
+        Args<Type> argTypes = _typeFlowAnalysis.argumentTypes(member)!;
         final uncheckedParameters =
             _typeFlowAnalysis.uncheckedParameters(member);
-        assert(argTypes != null);
 
         final int firstParamIndex =
             numTypeParams(member) + (hasReceiverArg(member) ? 1 : 0);
 
-        final positionalParams = member.function.positionalParameters;
+        final positionalParams = member.function!.positionalParameters;
         assert(argTypes.positionalCount ==
             firstParamIndex + positionalParams.length);
 
         for (int i = 0; i < positionalParams.length; i++) {
           _setInferredType(
               positionalParams[i], argTypes.values[firstParamIndex + i],
-              skipCheck: uncheckedParameters.contains(positionalParams[i]));
+              skipCheck: uncheckedParameters!.contains(positionalParams[i]));
         }
 
         // TODO(dartbug.com/32292): make sure parameters are sorted in kernel
         // AST and iterate parameters in parallel, without lookup.
         final names = argTypes.names;
         for (int i = 0; i < names.length; i++) {
-          final param = findNamedParameter(member.function, names[i]);
-          assert(param != null);
+          final param = findNamedParameter(member.function!, names[i])!;
           _setInferredType(param,
               argTypes.values[firstParamIndex + positionalParams.length + i],
-              skipCheck: uncheckedParameters.contains(param));
+              skipCheck: uncheckedParameters!.contains(param));
         }
 
         // TODO(alexmarkov): figure out how to pass receiver type.
@@ -521,7 +518,7 @@
     // interface target, and table dispatch calls need selector IDs for all
     // interface targets.
     if (member.isInstanceMember) {
-      final original = fieldMorpher.getOriginalMember(member);
+      final original = fieldMorpher.getOriginalMember(member)!;
       final attrs = new ProcedureAttributesMetadata(
           methodOrSetterCalledDynamically:
               _typeFlowAnalysis.isCalledDynamically(original),
@@ -689,11 +686,11 @@
   final Set<Member> _usedMembers = new Set<Member>();
   final Set<Extension> _usedExtensions = new Set<Extension>();
   final Set<Typedef> _usedTypedefs = new Set<Typedef>();
-  FieldMorpher fieldMorpher;
-  _TreeShakerTypeVisitor typeVisitor;
-  _TreeShakerConstantVisitor constantVisitor;
-  _TreeShakerPass1 _pass1;
-  _TreeShakerPass2 _pass2;
+  late final FieldMorpher fieldMorpher;
+  late final _TreeShakerTypeVisitor typeVisitor;
+  late final _TreeShakerConstantVisitor constantVisitor;
+  late final _TreeShakerPass1 _pass1;
+  late final _TreeShakerPass2 _pass2;
 
   TreeShaker(Component component, this.typeFlowAnalysis,
       {this.treeShakeWriteOnlyFields: true}) {
@@ -734,7 +731,7 @@
               (!f.isStatic &&
                   f.initializer != null &&
                   isFieldInitializerReachable(f) &&
-                  mayHaveSideEffects(f.initializer)) ||
+                  mayHaveSideEffects(f.initializer!)) ||
               (f.isLate && f.isFinal)) ||
       isMemberReferencedFromNativeCode(f) ||
       _isInstanceFieldOfAllocatedEnum(f);
@@ -745,8 +742,8 @@
   bool _isInstanceFieldOfAllocatedEnum(Field node) =>
       !node.isStatic &&
       node.enclosingClass != null &&
-      node.enclosingClass.isEnum &&
-      isClassAllocated(node.enclosingClass);
+      node.enclosingClass!.isEnum &&
+      isClassAllocated(node.enclosingClass!);
 
   void addClassUsedInType(Class c) {
     if (_classesUsedInType.add(c)) {
@@ -777,7 +774,7 @@
         _usedClasses.add(enclosingClass);
       }
 
-      FunctionNode func = null;
+      FunctionNode? func = null;
       if (m is Field) {
         m.type.accept(typeVisitor);
       } else if (m is Procedure) {
@@ -786,19 +783,19 @@
           m.stubTarget = fieldMorpher.adjustInstanceCallTarget(
               m.concreteForwardingStubTarget,
               isSetter: m.isSetter);
-          addUsedMember(m.concreteForwardingStubTarget);
+          addUsedMember(m.concreteForwardingStubTarget!);
         }
         if (m.abstractForwardingStubTarget != null) {
           m.stubTarget = fieldMorpher.adjustInstanceCallTarget(
               m.abstractForwardingStubTarget,
               isSetter: m.isSetter);
-          addUsedMember(m.abstractForwardingStubTarget);
+          addUsedMember(m.abstractForwardingStubTarget!);
         }
         if (m.memberSignatureOrigin != null) {
           m.stubTarget = fieldMorpher.adjustInstanceCallTarget(
               m.memberSignatureOrigin,
               isSetter: m.isSetter);
-          addUsedMember(m.memberSignatureOrigin);
+          addUsedMember(m.memberSignatureOrigin!);
         }
       } else if (m is Constructor) {
         func = m.function;
@@ -821,8 +818,7 @@
         final extension = m.enclosingLibrary.extensions.firstWhere((extension) {
           return extension.members
               .any((descriptor) => descriptor.member.asMember == m);
-        }, orElse: () => null);
-        assert(extension != null);
+        });
 
         // Ensure we retain the [Extension] itself (though members might be
         // shaken)
@@ -844,7 +840,7 @@
     if (_usedExtensions.add(node)) {
       node.annotations = const <Expression>[];
       _pass1.transformTypeParameterList(node.typeParameters, node);
-      node.onType?.accept(typeVisitor);
+      node.onType.accept(typeVisitor);
     }
   }
 
@@ -898,7 +894,7 @@
           isAbstract: true, fileUri: field.fileUri);
     }
     accessor.fileOffset = field.fileOffset;
-    field.enclosingClass.addProcedure(accessor);
+    field.enclosingClass!.addProcedure(accessor);
     _removedFields[accessor] = field;
     shaker.addUsedMember(accessor);
     return accessor;
@@ -908,7 +904,7 @@
   /// If necessary, creates a getter or setter as a replacement if target is a
   /// field which is going to be removed by the tree shaker.
   /// This method is used during tree shaker pass 1.
-  Member adjustInstanceCallTarget(Member target, {bool isSetter = false}) {
+  Member? adjustInstanceCallTarget(Member? target, {bool isSetter = false}) {
     if (target is Field && !shaker.retainField(target)) {
       final targets =
           isSetter ? _settersForRemovedFields : _gettersForRemovedFields;
@@ -923,9 +919,9 @@
 
   /// Return a member which replaced [target] in instance calls.
   /// This method can be used after tree shaking to discover replacement.
-  Member getMorphedMember(Member target, {bool isSetter = false}) {
-    if (target == null) {
-      return null;
+  Member? getMorphedMember(Member? target, {bool isSetter = false}) {
+    if (target is! Field) {
+      return target;
     }
     final targets =
         isSetter ? _settersForRemovedFields : _gettersForRemovedFields;
@@ -934,7 +930,7 @@
 
   /// Return original member which was replaced by [target] in instance calls.
   /// This method can be used after tree shaking.
-  Member getOriginalMember(Member target) {
+  Member? getOriginalMember(Member? target) {
     if (target == null) {
       return null;
     }
@@ -994,16 +990,15 @@
   final TreeShaker shaker;
   final FieldMorpher fieldMorpher;
   final TypeEnvironment environment;
-  Procedure _unsafeCast;
 
-  StaticTypeContext _staticTypeContext;
-  Member _currentMember;
+  StaticTypeContext? _staticTypeContext;
+  Member? _currentMember;
 
   StaticTypeContext get staticTypeContext =>
       _staticTypeContext ??= StaticTypeContext(currentMember, environment);
 
-  Member get currentMember => _currentMember;
-  set currentMember(Member m) {
+  Member get currentMember => _currentMember!;
+  set currentMember(Member? m) {
     _currentMember = m;
     _staticTypeContext = null;
   }
@@ -1022,7 +1017,7 @@
   }
 
   List<Expression> _flattenArguments(Arguments arguments,
-      {Expression receiver}) {
+      {Expression? receiver}) {
     final args = <Expression>[];
     if (receiver != null) {
       args.add(receiver);
@@ -1035,9 +1030,9 @@
   bool _isThrowExpression(Expression expr) {
     for (;;) {
       if (expr is Let) {
-        expr = (expr as Let).body;
+        expr = expr.body;
       } else if (expr is BlockExpression) {
-        expr = (expr as BlockExpression).value;
+        expr = expr.value;
       } else {
         break;
       }
@@ -1068,7 +1063,7 @@
     return BlockExpression(Block(statements), value);
   }
 
-  TreeNode _makeUnreachableCall(List<Expression> args) {
+  Expression _makeUnreachableCall(List<Expression> args) {
     Expression node;
     final int last = args.indexWhere(_isThrowExpression);
     if (last >= 0) {
@@ -1090,12 +1085,12 @@
         new VariableDeclaration(null, initializer: _makeUnreachableCall(args)));
   }
 
-  NarrowNotNull _getNullTest(TreeNode node) =>
+  NarrowNotNull? _getNullTest(TreeNode node) =>
       shaker.typeFlowAnalysis.nullTest(node);
 
-  TreeNode _visitAssertNode(TreeNode node, TreeNode removalSentinel) {
+  TreeNode _visitAssertNode(TreeNode node, TreeNode? removalSentinel) {
     if (kRemoveAsserts) {
-      return removalSentinel;
+      return removalSentinel!;
     } else {
       node.transformOrRemoveChildren(this);
       return node;
@@ -1103,31 +1098,31 @@
   }
 
   @override
-  DartType visitDartType(DartType node, DartType removalSentinel) {
+  DartType visitDartType(DartType node, DartType? removalSentinel) {
     node.accept(shaker.typeVisitor);
     return node;
   }
 
   @override
-  Supertype visitSupertype(Supertype node, Supertype removalSentinel) {
+  Supertype visitSupertype(Supertype node, Supertype? removalSentinel) {
     node.accept(shaker.typeVisitor);
     return node;
   }
 
   @override
-  TreeNode visitTypedef(Typedef node, TreeNode removalSentinel) {
+  TreeNode visitTypedef(Typedef node, TreeNode? removalSentinel) {
     return node; // Do not go deeper.
   }
 
   @override
-  Extension visitExtension(Extension node, TreeNode removalSentinel) {
+  TreeNode 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 removalSentinel) {
+  TreeNode visitClass(Class node, TreeNode? removalSentinel) {
     if (shaker.isClassAllocated(node) ||
         shaker.isClassReferencedFromNativeCode(node)) {
       shaker.addClassUsedInType(node);
@@ -1140,7 +1135,7 @@
   }
 
   @override
-  TreeNode defaultMember(Member node, TreeNode removalSentinel) {
+  TreeNode defaultMember(Member node, TreeNode? removalSentinel) {
     currentMember = node;
     if (shaker.isMemberBodyReachable(node)) {
       if (kPrintTrace) {
@@ -1160,7 +1155,7 @@
   }
 
   @override
-  TreeNode visitField(Field node, TreeNode removalSentinel) {
+  TreeNode visitField(Field node, TreeNode? removalSentinel) {
     currentMember = node;
     if (shaker.retainField(node)) {
       if (kPrintTrace) {
@@ -1185,21 +1180,21 @@
 
   @override
   TreeNode visitInstanceInvocation(
-      InstanceInvocation node, TreeNode removalSentinel) {
+      InstanceInvocation node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(
           _flattenArguments(node.arguments, receiver: node.receiver));
     }
-    node.interfaceTarget =
-        fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+    node.interfaceTarget = fieldMorpher
+        .adjustInstanceCallTarget(node.interfaceTarget) as Procedure;
     shaker.addUsedMember(node.interfaceTarget);
     return node;
   }
 
   @override
   TreeNode visitDynamicInvocation(
-      DynamicInvocation node, TreeNode removalSentinel) {
+      DynamicInvocation node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(
@@ -1210,7 +1205,7 @@
 
   @override
   TreeNode visitLocalFunctionInvocation(
-      LocalFunctionInvocation node, TreeNode removalSentinel) {
+      LocalFunctionInvocation node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(_flattenArguments(node.arguments));
@@ -1220,7 +1215,7 @@
 
   @override
   TreeNode visitFunctionInvocation(
-      FunctionInvocation node, TreeNode removalSentinel) {
+      FunctionInvocation node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(
@@ -1230,24 +1225,24 @@
   }
 
   @override
-  TreeNode visitEqualsCall(EqualsCall node, TreeNode removalSentinel) {
+  TreeNode visitEqualsCall(EqualsCall node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.left, node.right]);
     }
-    node.interfaceTarget =
-        fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+    node.interfaceTarget = fieldMorpher
+        .adjustInstanceCallTarget(node.interfaceTarget) as Procedure;
     shaker.addUsedMember(node.interfaceTarget);
     return node;
   }
 
   @override
-  TreeNode visitEqualsNull(EqualsNull node, TreeNode removalSentinel) {
+  TreeNode visitEqualsNull(EqualsNull node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.expression]);
     }
-    final nullTest = _getNullTest(node);
+    final nullTest = _getNullTest(node)!;
     if (nullTest.isAlwaysNull || nullTest.isAlwaysNotNull) {
       return _evaluateArguments([node.expression],
           BoolLiteral(nullTest.isAlwaysNull)..fileOffset = node.fileOffset);
@@ -1256,13 +1251,13 @@
   }
 
   @override
-  TreeNode visitInstanceGet(InstanceGet node, TreeNode removalSentinel) {
+  TreeNode visitInstanceGet(InstanceGet node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.receiver]);
     } else {
       node.interfaceTarget =
-          fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+          fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget)!;
       shaker.addUsedMember(node.interfaceTarget);
       return node;
     }
@@ -1270,20 +1265,20 @@
 
   @override
   TreeNode visitInstanceTearOff(
-      InstanceTearOff node, TreeNode removalSentinel) {
+      InstanceTearOff node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.receiver]);
     } else {
-      node.interfaceTarget =
-          fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+      node.interfaceTarget = fieldMorpher
+          .adjustInstanceCallTarget(node.interfaceTarget) as Procedure;
       shaker.addUsedMember(node.interfaceTarget);
       return node;
     }
   }
 
   @override
-  TreeNode visitDynamicGet(DynamicGet node, TreeNode removalSentinel) {
+  TreeNode visitDynamicGet(DynamicGet node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.receiver]);
@@ -1294,7 +1289,7 @@
 
   @override
   TreeNode visitFunctionTearOff(
-      FunctionTearOff node, TreeNode removalSentinel) {
+      FunctionTearOff node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.receiver]);
@@ -1304,20 +1299,20 @@
   }
 
   @override
-  TreeNode visitInstanceSet(InstanceSet node, TreeNode removalSentinel) {
+  TreeNode visitInstanceSet(InstanceSet node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.receiver, node.value]);
     } else {
       node.interfaceTarget = fieldMorpher
-          .adjustInstanceCallTarget(node.interfaceTarget, isSetter: true);
+          .adjustInstanceCallTarget(node.interfaceTarget, isSetter: true)!;
       shaker.addUsedMember(node.interfaceTarget);
       return node;
     }
   }
 
   @override
-  TreeNode visitDynamicSet(DynamicSet node, TreeNode removalSentinel) {
+  TreeNode visitDynamicSet(DynamicSet node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.receiver, node.value]);
@@ -1328,15 +1323,15 @@
 
   @override
   TreeNode visitSuperMethodInvocation(
-      SuperMethodInvocation node, TreeNode removalSentinel) {
+      SuperMethodInvocation node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(_flattenArguments(node.arguments));
     } else {
-      node.interfaceTarget =
-          fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+      node.interfaceTarget = fieldMorpher
+          .adjustInstanceCallTarget(node.interfaceTarget) as Procedure?;
       if (node.interfaceTarget != null) {
-        shaker.addUsedMember(node.interfaceTarget);
+        shaker.addUsedMember(node.interfaceTarget!);
       }
       return node;
     }
@@ -1344,7 +1339,7 @@
 
   @override
   TreeNode visitSuperPropertyGet(
-      SuperPropertyGet node, TreeNode removalSentinel) {
+      SuperPropertyGet node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([]);
@@ -1352,7 +1347,7 @@
       node.interfaceTarget =
           fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
       if (node.interfaceTarget != null) {
-        shaker.addUsedMember(node.interfaceTarget);
+        shaker.addUsedMember(node.interfaceTarget!);
       }
       return node;
     }
@@ -1360,7 +1355,7 @@
 
   @override
   TreeNode visitSuperPropertySet(
-      SuperPropertySet node, TreeNode removalSentinel) {
+      SuperPropertySet node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.value]);
@@ -1368,7 +1363,7 @@
       node.interfaceTarget = fieldMorpher
           .adjustInstanceCallTarget(node.interfaceTarget, isSetter: true);
       if (node.interfaceTarget != null) {
-        shaker.addUsedMember(node.interfaceTarget);
+        shaker.addUsedMember(node.interfaceTarget!);
       }
       return node;
     }
@@ -1376,7 +1371,7 @@
 
   @override
   TreeNode visitStaticInvocation(
-      StaticInvocation node, TreeNode removalSentinel) {
+      StaticInvocation node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(_flattenArguments(node.arguments));
@@ -1390,7 +1385,7 @@
   }
 
   @override
-  TreeNode visitStaticGet(StaticGet node, TreeNode removalSentinel) {
+  TreeNode visitStaticGet(StaticGet node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([]);
@@ -1405,13 +1400,13 @@
   }
 
   @override
-  Constant visitConstant(Constant node, Constant removalSentinel) {
+  Constant visitConstant(Constant node, Constant? removalSentinel) {
     shaker.constantVisitor.analyzeConstant(node);
     return node;
   }
 
   @override
-  TreeNode visitStaticSet(StaticSet node, TreeNode removalSentinel) {
+  TreeNode visitStaticSet(StaticSet node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall([node.value]);
@@ -1428,7 +1423,7 @@
 
   @override
   TreeNode visitConstructorInvocation(
-      ConstructorInvocation node, TreeNode removalSentinel) {
+      ConstructorInvocation node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableCall(_flattenArguments(node.arguments));
@@ -1444,7 +1439,7 @@
 
   @override
   TreeNode visitRedirectingInitializer(
-      RedirectingInitializer node, TreeNode removalSentinel) {
+      RedirectingInitializer node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableInitializer(_flattenArguments(node.arguments));
@@ -1457,7 +1452,7 @@
 
   @override
   TreeNode visitSuperInitializer(
-      SuperInitializer node, TreeNode removalSentinel) {
+      SuperInitializer node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableInitializer(_flattenArguments(node.arguments));
@@ -1469,7 +1464,7 @@
 
   @override
   TreeNode visitFieldInitializer(
-      FieldInitializer node, TreeNode removalSentinel) {
+      FieldInitializer node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
       return _makeUnreachableInitializer([node.value]);
@@ -1482,7 +1477,7 @@
           return LocalInitializer(
               VariableDeclaration(null, initializer: node.value));
         } else {
-          return removalSentinel;
+          return removalSentinel!;
         }
       }
       return node;
@@ -1491,18 +1486,18 @@
 
   @override
   TreeNode visitAssertStatement(
-      AssertStatement node, TreeNode removalSentinel) {
+      AssertStatement node, TreeNode? removalSentinel) {
     return _visitAssertNode(node, removalSentinel);
   }
 
   @override
-  TreeNode visitAssertBlock(AssertBlock node, TreeNode removalSentinel) {
+  TreeNode visitAssertBlock(AssertBlock node, TreeNode? removalSentinel) {
     return _visitAssertNode(node, removalSentinel);
   }
 
   @override
   TreeNode visitAssertInitializer(
-      AssertInitializer node, TreeNode removalSentinel) {
+      AssertInitializer node, TreeNode? removalSentinel) {
     return _visitAssertNode(node, removalSentinel);
   }
 
@@ -1520,21 +1515,21 @@
 
   // Returns Block corresponding to the given extended bool literal,
   // or null if the expression is a simple bool literal.
-  Block _getExtendedBoolLiteralBlock(Expression expr) =>
+  Block? _getExtendedBoolLiteralBlock(Expression expr) =>
       (expr is BoolLiteral) ? null : (expr as BlockExpression).body;
 
   @override
-  TreeNode visitIfStatement(IfStatement node, TreeNode removalSentinel) {
+  TreeNode visitIfStatement(IfStatement node, TreeNode? removalSentinel) {
     final condition = transform(node.condition);
     if (_isExtendedBoolLiteral(condition)) {
       final bool conditionValue = _getExtendedBoolLiteralValue(condition);
-      final Block conditionBlock = _getExtendedBoolLiteralBlock(condition);
-      ast.Statement body;
+      final Block? conditionBlock = _getExtendedBoolLiteralBlock(condition);
+      ast.Statement? body;
       if (conditionValue) {
         body = transform(node.then);
       } else {
         if (node.otherwise != null) {
-          body = transformOrRemoveStatement(node.otherwise);
+          body = transformOrRemoveStatement(node.otherwise!);
         }
       }
       if (conditionBlock != null) {
@@ -1549,7 +1544,7 @@
     node.condition = condition..parent = node;
     node.then = transform(node.then)..parent = node;
     if (node.otherwise != null) {
-      node.otherwise = transformOrRemoveStatement(node.otherwise);
+      node.otherwise = transformOrRemoveStatement(node.otherwise!);
       node.otherwise?.parent = node;
     }
     return node;
@@ -1557,7 +1552,7 @@
 
   @override
   visitConditionalExpression(
-      ConditionalExpression node, TreeNode removalSentinel) {
+      ConditionalExpression node, TreeNode? removalSentinel) {
     final condition = transform(node.condition);
     if (_isExtendedBoolLiteral(condition)) {
       final bool value = _getExtendedBoolLiteralValue(condition);
@@ -1578,7 +1573,7 @@
   }
 
   @override
-  TreeNode visitNot(Not node, TreeNode removalSentinel) {
+  TreeNode visitNot(Not node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
     final operand = node.operand;
     if (_isExtendedBoolLiteral(operand)) {
@@ -1595,7 +1590,7 @@
 
   @override
   TreeNode visitLogicalExpression(
-      LogicalExpression node, TreeNode removalSentinel) {
+      LogicalExpression node, TreeNode? removalSentinel) {
     final left = transform(node.left);
     final operatorEnum = node.operatorEnum;
     if (_isExtendedBoolLiteral(left)) {
@@ -1621,8 +1616,8 @@
   }
 
   @override
-  TreeNode visitIsExpression(IsExpression node, TreeNode removalSentinel) {
-    TypeCheck check = shaker.typeFlowAnalysis.isTest(node);
+  TreeNode visitIsExpression(IsExpression node, TreeNode? removalSentinel) {
+    TypeCheck? check = shaker.typeFlowAnalysis.isTest(node);
     if (check != null && (check.alwaysFail || check.alwaysPass)) {
       final operand = transform(node.operand);
       final result = BoolLiteral(!check.alwaysFail)
@@ -1634,9 +1629,9 @@
   }
 
   @override
-  TreeNode visitAsExpression(AsExpression node, TreeNode removalSentinel) {
+  TreeNode visitAsExpression(AsExpression node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
-    TypeCheck check = shaker.typeFlowAnalysis.explicitCast(node);
+    TypeCheck? check = shaker.typeFlowAnalysis.explicitCast(node);
     if (check != null && check.alwaysPass) {
       return StaticInvocation(
           unsafeCast, Arguments([node.operand], types: [node.type]))
@@ -1646,9 +1641,9 @@
   }
 
   @override
-  TreeNode visitNullCheck(NullCheck node, TreeNode removalSentinel) {
+  TreeNode visitNullCheck(NullCheck node, TreeNode? removalSentinel) {
     node.transformOrRemoveChildren(this);
-    final nullTest = _getNullTest(node);
+    final nullTest = _getNullTest(node)!;
     if (nullTest.isAlwaysNotNull) {
       return StaticInvocation(
           unsafeCast,
@@ -1659,12 +1654,9 @@
     return node;
   }
 
-  Procedure get unsafeCast {
-    _unsafeCast ??= shaker.typeFlowAnalysis.environment.coreTypes.index
-        .getTopLevelMember('dart:_internal', 'unsafeCast');
-    assert(_unsafeCast != null);
-    return _unsafeCast;
-  }
+  late final Procedure unsafeCast = shaker
+      .typeFlowAnalysis.environment.coreTypes.index
+      .getTopLevelProcedure('dart:_internal', 'unsafeCast');
 }
 
 /// The second pass of [TreeShaker]. It is called after set of used
@@ -1680,7 +1672,7 @@
   void transformComponent(Component component) {
     component.transformOrRemoveChildren(this);
     for (Source source in component.uriToSource.values) {
-      source?.constantCoverageConstructors?.removeWhere((Reference reference) {
+      source.constantCoverageConstructors?.removeWhere((Reference reference) {
         Member node = reference.asMember;
         return !shaker.isMemberUsed(node);
       });
@@ -1688,7 +1680,7 @@
   }
 
   @override
-  TreeNode visitLibrary(Library node, TreeNode removalSentinel) {
+  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.
@@ -1708,12 +1700,12 @@
   }
 
   @override
-  Typedef visitTypedef(Typedef node, TreeNode removalSentinel) {
-    return shaker.isTypedefUsed(node) ? node : removalSentinel;
+  TreeNode visitTypedef(Typedef node, TreeNode? removalSentinel) {
+    return shaker.isTypedefUsed(node) ? node : removalSentinel!;
   }
 
   @override
-  Class visitClass(Class node, TreeNode removalSentinel) {
+  TreeNode visitClass(Class node, TreeNode? removalSentinel) {
     if (!shaker.isClassUsed(node)) {
       debugPrint('Dropped class ${node.name}');
       // Ensure that kernel file writer will not be able to
@@ -1724,7 +1716,7 @@
           "been repurposed for ${node.reference.node}.");
       node.reference.canonicalName?.unbind();
       Statistics.classesDropped++;
-      return removalSentinel; // Remove the class.
+      return removalSentinel!; // Remove the class.
     }
 
     if (!shaker.isClassUsedInType(node)) {
@@ -1755,7 +1747,7 @@
   }
 
   @override
-  Member defaultMember(Member node, TreeNode removalSentinel) {
+  TreeNode defaultMember(Member node, TreeNode? removalSentinel) {
     if (!shaker.isMemberUsed(node)) {
       // Ensure that kernel file writer will not be able to
       // write a dangling reference to the deleted member.
@@ -1767,10 +1759,10 @@
         node.getterReference.canonicalName?.unbind();
         if (node.hasSetter) {
           assert(
-              node.setterReference.node == node,
+              node.setterReference!.node == node,
               "Trying to remove canonical name from reference on $node which "
-              "has been repurposed for ${node.setterReference.node}.");
-          node.setterReference.canonicalName?.unbind();
+              "has been repurposed for ${node.setterReference!.node}.");
+          node.setterReference!.canonicalName?.unbind();
         }
       } else {
         assert(
@@ -1780,13 +1772,13 @@
         node.reference.canonicalName?.unbind();
       }
       Statistics.membersDropped++;
-      return removalSentinel;
+      return removalSentinel!;
     }
 
     if (!shaker.isMemberBodyReachable(node)) {
       if (node is Procedure) {
         // Remove body of unused member.
-        if (!node.isStatic && node.enclosingClass.isAbstract) {
+        if (!node.isStatic && node.enclosingClass!.isAbstract) {
           node.isAbstract = true;
           node.function.body = null;
         } else {
@@ -1829,7 +1821,7 @@
   }
 
   @override
-  Extension visitExtension(Extension node, TreeNode removalSentinel) {
+  TreeNode visitExtension(Extension node, TreeNode? removalSentinel) {
     if (shaker.isExtensionUsed(node)) {
       int writeIndex = 0;
       for (int i = 0; i < node.members.length; ++i) {
@@ -1840,7 +1832,7 @@
         // member was already removed or it will be removed later.
         final Reference memberReference = descriptor.member;
         final bool isBound = memberReference.node != null;
-        if (isBound && shaker.isMemberUsed(memberReference.node)) {
+        if (isBound && shaker.isMemberUsed(memberReference.asMember)) {
           node.members[writeIndex++] = descriptor;
         }
       }
@@ -1850,7 +1842,7 @@
       assert(node.members.length > 0);
       return node;
     }
-    return removalSentinel;
+    return removalSentinel!;
   }
 
   void _makeUnreachableBody(FunctionNode function) {
@@ -1871,7 +1863,7 @@
   }
 
   @override
-  TreeNode defaultTreeNode(TreeNode node, TreeNode removalSentinel) {
+  TreeNode defaultTreeNode(TreeNode node, TreeNode? removalSentinel) {
     return node; // Do not traverse into other nodes.
   }
 }
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 588512c..3ed7b9b 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -2,10 +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 file.
 
-// @dart=2.9
-
 /// Declares the type system used by global type flow analysis.
-library vm.transformations.type_flow.types;
 
 import 'dart:core' hide Type;
 
@@ -138,10 +135,7 @@
   /// values can flow through the program.
   Type specializeTypeCone(TFClass base, {bool allowWideCone = false});
 
-  Type _cachedIntType;
-  Type get intType {
-    return _cachedIntType ??= fromStaticType(coreTypes.intLegacyRawType, true);
-  }
+  late final Type intType = fromStaticType(coreTypes.intLegacyRawType, true);
 }
 
 /// Base class for type expressions.
@@ -151,7 +145,7 @@
 
   /// Returns computed type of this type expression.
   /// [types] is the list of types computed for the statements in the summary.
-  Type getComputedType(List<Type> types);
+  Type getComputedType(List<Type?> types);
 }
 
 /// Kind of a subtype test: subtype/cast/'as' test or instance check/'is' test.
@@ -174,7 +168,7 @@
   /// Create a type representing arbitrary nullable object (`dynamic`).
   factory Type.nullableAny() => new NullableType(const AnyType());
 
-  Class getConcreteClass(TypeHierarchy typeHierarchy) => null;
+  Class? getConcreteClass(TypeHierarchy typeHierarchy) => null;
 
   bool isSubtypeOf(TypeHierarchy typeHierarchy, Class cls) => false;
 
@@ -185,7 +179,7 @@
       RuntimeType runtimeType, SubtypeTestKind kind);
 
   @override
-  Type getComputedType(List<Type> types) => this;
+  Type getComputedType(List<Type?> types) => this;
 
   /// Order of precedence for evaluation of union/intersection.
   int get order;
@@ -260,7 +254,6 @@
   final Type baseType;
 
   NullableType(this.baseType) {
-    assert(baseType != null);
     assert(baseType is! NullableType);
   }
 
@@ -387,7 +380,9 @@
 class SetType extends Type {
   /// List of concrete types, sorted by classId.
   final List<ConcreteType> types;
-  int _hashCode;
+
+  @override
+  late final int hashCode = _computeHashCode();
 
   /// Creates a new SetType using list of concrete types sorted by classId.
   SetType(this.types) {
@@ -395,9 +390,6 @@
     assert(isSorted(types));
   }
 
-  @override
-  int get hashCode => _hashCode ??= _computeHashCode();
-
   int _computeHashCode() {
     int hash = 1237;
     for (var t in types) {
@@ -470,8 +462,8 @@
     return types;
   }
 
-  static List<ConcreteType> _intersectLists(
-      List<ConcreteType> types1, List<ConcreteType> types2) {
+  static List<ConcreteType> _intersectLists(List<ConcreteType> types1,
+      List<ConcreteType> types2, TypeHierarchy typeHierarchy) {
     int i1 = 0;
     int i2 = 0;
     List<ConcreteType> types = <ConcreteType>[];
@@ -491,9 +483,9 @@
             t2.constant == null) {
           types.add(t1);
         } else {
-          final intersect = t1.intersection(t2, null);
+          final intersect = t1.intersection(t2, typeHierarchy);
           if (intersect is! EmptyType) {
-            types.add(intersect);
+            types.add(intersect as ConcreteType);
           }
         }
         ++i1;
@@ -558,7 +550,8 @@
       return other.intersection(this, typeHierarchy);
     }
     if (other is SetType) {
-      List<ConcreteType> list = _intersectLists(types, other.types);
+      List<ConcreteType> list =
+          _intersectLists(types, other.types, typeHierarchy);
       final size = list.length;
       if (size == 0) {
         return const EmptyType();
@@ -594,7 +587,7 @@
   ConeType(this.cls);
 
   @override
-  Class getConcreteClass(TypeHierarchy typeHierarchy) => typeHierarchy
+  Class? getConcreteClass(TypeHierarchy typeHierarchy) => typeHierarchy
       .specializeTypeCone(cls, allowWideCone: true)
       .getConcreteClass(typeHierarchy);
 
@@ -696,7 +689,7 @@
   WideConeType(TFClass cls) : super(cls);
 
   @override
-  Class getConcreteClass(TypeHierarchy typeHierarchy) => null;
+  Class? getConcreteClass(TypeHierarchy typeHierarchy) => null;
 
   @override
   int get hashCode => (cls.id + 41) & kHashMask;
@@ -783,7 +776,9 @@
 /// or `null` object).
 class ConcreteType extends Type implements Comparable<ConcreteType> {
   final TFClass cls;
-  int _hashCode;
+
+  @override
+  late final int hashCode = _computeHashCode();
 
   // May be null if there are no type arguments constraints. The type arguments
   // should represent type sets, i.e. `UnknownType` or `RuntimeType`. The type
@@ -796,19 +791,19 @@
   // 'numImmediateTypeArgs' is the length of the prefix of 'typeArgs' which
   // holds the type arguments to the class itself.
   final int numImmediateTypeArgs;
-  final List<Type> typeArgs;
+  final List<Type>? typeArgs;
 
   // May be null if constant value is not inferred.
-  final Constant constant;
+  final Constant? constant;
 
-  ConcreteType(this.cls, [List<Type> typeArgs_, this.constant])
+  ConcreteType(this.cls, [List<Type>? typeArgs_, this.constant])
       : typeArgs = typeArgs_,
         numImmediateTypeArgs =
             typeArgs_ != null ? cls.classNode.typeParameters.length : 0 {
     // TODO(alexmarkov): support closures
     assert(!cls.classNode.isAbstract);
     assert(typeArgs == null || cls.classNode.typeParameters.isNotEmpty);
-    assert(typeArgs == null || typeArgs.any((t) => t is RuntimeType));
+    assert(typeArgs == null || typeArgs!.any((t) => t is RuntimeType));
   }
 
   ConcreteType get raw => cls.concreteType;
@@ -839,7 +834,7 @@
 
       if (rhs.typeArguments.isEmpty) return true;
 
-      List<Type> usableTypeArgs = typeArgs;
+      List<Type>? usableTypeArgs = typeArgs;
       if (usableTypeArgs == null) {
         if (cls.classNode.typeParameters.isEmpty) {
           usableTypeArgs =
@@ -862,7 +857,7 @@
         }
         assert(ta is RuntimeType);
         if (!ta.isSubtypeOfRuntimeType(
-            typeHierarchy, runtimeType.typeArgs[i], SubtypeTestKind.Subtype)) {
+            typeHierarchy, runtimeType.typeArgs![i], SubtypeTestKind.Subtype)) {
           return false;
         }
       }
@@ -877,29 +872,26 @@
         } else {
           final interfaceOffset = typeHierarchy.genericInterfaceOffsetFor(
               cls.classNode, typeHierarchy.coreTypes.futureClass);
-          typeArg = typeArgs[interfaceOffset];
+          typeArg = typeArgs![interfaceOffset];
         }
         final RuntimeType lhs =
             typeArg is RuntimeType ? typeArg : RuntimeType(DynamicType(), null);
         return lhs.isSubtypeOfRuntimeType(
-            typeHierarchy, runtimeType.typeArgs[0], SubtypeTestKind.Subtype);
+            typeHierarchy, runtimeType.typeArgs![0], SubtypeTestKind.Subtype);
       } else {
         return isSubtypeOfRuntimeType(
-            typeHierarchy, runtimeType.typeArgs[0], SubtypeTestKind.Subtype);
+            typeHierarchy, runtimeType.typeArgs![0], SubtypeTestKind.Subtype);
       }
     }
     return false;
   }
 
-  @override
-  int get hashCode => _hashCode ??= _computeHashCode();
-
   int _computeHashCode() {
     int hash = cls.hashCode ^ 0x1234 & kHashMask;
     // We only need to hash the first type arguments vector, since the type
     // arguments of the implemented interfaces are implied by it.
     for (int i = 0; i < numImmediateTypeArgs; ++i) {
-      hash = (((hash * 31) & kHashMask) + typeArgs[i].hashCode) & kHashMask;
+      hash = (((hash * 31) & kHashMask) + typeArgs![i].hashCode) & kHashMask;
     }
     hash = ((hash * 31) & kHashMask) + constant.hashCode;
     return hash;
@@ -915,7 +907,7 @@
       }
       if (this.typeArgs != null) {
         for (int i = 0; i < numImmediateTypeArgs; ++i) {
-          if (this.typeArgs[i] != other.typeArgs[i]) {
+          if (this.typeArgs![i] != other.typeArgs![i]) {
             return false;
           }
         }
@@ -942,10 +934,10 @@
     final StringBuffer buf = new StringBuffer();
     buf.write("_T (${cls}");
     if (typeArgs != null) {
-      buf.write("<${typeArgs.take(numImmediateTypeArgs).join(', ')}>");
+      buf.write("<${typeArgs!.take(numImmediateTypeArgs).join(', ')}>");
     }
     if (constant != null) {
-      buf.write(", ${nodeToText(constant)}");
+      buf.write(", ${nodeToText(constant!)}");
     }
     buf.write(")");
     return buf.toString();
@@ -997,17 +989,21 @@
         return this;
       }
 
-      List<Type> mergedTypeArgs;
-      if (typeArgs == null) {
-        mergedTypeArgs = other.typeArgs;
-      } else if (other.typeArgs == null) {
-        mergedTypeArgs = typeArgs;
+      List<Type>? mergedTypeArgs;
+      final thisTypeArgs = this.typeArgs;
+      final otherTypeArgs = other.typeArgs;
+      if (thisTypeArgs == null) {
+        mergedTypeArgs = otherTypeArgs;
+      } else if (otherTypeArgs == null) {
+        mergedTypeArgs = thisTypeArgs;
       } else {
-        mergedTypeArgs = new List<Type>.filled(typeArgs.length, null);
+        assert(thisTypeArgs.length == otherTypeArgs.length);
+        mergedTypeArgs =
+            new List<Type>.filled(thisTypeArgs.length, const EmptyType());
         bool hasRuntimeType = false;
-        for (int i = 0; i < typeArgs.length; ++i) {
+        for (int i = 0; i < thisTypeArgs.length; ++i) {
           final merged =
-              typeArgs[i].intersection(other.typeArgs[i], typeHierarchy);
+              thisTypeArgs[i].intersection(otherTypeArgs[i], typeHierarchy);
           if (merged is EmptyType) {
             return const EmptyType();
           } else if (merged is RuntimeType) {
@@ -1020,7 +1016,7 @@
         }
       }
 
-      Constant mergedConstant;
+      Constant? mergedConstant;
       if (constant == null) {
         mergedConstant = other.constant;
       } else if (other.constant == null || constant == other.constant) {
@@ -1062,7 +1058,7 @@
   final DartType _type; // Doesn't contain type args.
 
   final int numImmediateTypeArgs;
-  final List<RuntimeType> typeArgs;
+  final List<RuntimeType>? typeArgs;
 
   RuntimeType(DartType type, this.typeArgs)
       : _type = type,
@@ -1070,14 +1066,12 @@
             ? type.classNode.typeParameters.length
             : (type is FutureOrType ? 1 : 0) {
     if (_type is InterfaceType && numImmediateTypeArgs > 0) {
-      assert(typeArgs != null);
-      assert(typeArgs.length >= numImmediateTypeArgs);
+      assert(typeArgs!.length >= numImmediateTypeArgs);
       assert((_type as InterfaceType)
           .typeArguments
           .every((t) => t == const DynamicType()));
     } else if (_type is FutureOrType) {
-      assert(typeArgs != null);
-      assert(typeArgs.length >= numImmediateTypeArgs);
+      assert(typeArgs!.length >= numImmediateTypeArgs);
       DartType typeArgument = (_type as FutureOrType).typeArgument;
       assert(typeArgument == const DynamicType());
     } else {
@@ -1098,25 +1092,27 @@
     final type = _type;
     if (type is InterfaceType && typeArgs != null) {
       final klass = type.classNode;
-      final typeArguments = typeArgs
+      final typeArguments = typeArgs!
           .take(klass.typeParameters.length)
           .map((pt) => pt.representedType)
           .toList();
       return new InterfaceType(klass, type.nullability, typeArguments);
     } else if (type is FutureOrType) {
-      return new FutureOrType(typeArgs[0].representedType, type.nullability);
+      return new FutureOrType(typeArgs![0].representedType, type.nullability);
     } else {
       return type;
     }
   }
 
   @override
-  int get hashCode {
+  late final int hashCode = _computeHashCode();
+
+  int _computeHashCode() {
     int hash = _type.hashCode ^ 0x1234 & kHashMask;
     // Only hash by the type arguments of the class. The type arguments of
     // supertypes are are implied by them.
     for (int i = 0; i < numImmediateTypeArgs; ++i) {
-      hash = (((hash * 31) & kHashMask) + typeArgs[i].hashCode) & kHashMask;
+      hash = (((hash * 31) & kHashMask) + typeArgs![i].hashCode) & kHashMask;
     }
     return hash;
   }
@@ -1127,7 +1123,7 @@
     if (other is RuntimeType) {
       if (other._type != _type) return false;
       assert(numImmediateTypeArgs == other.numImmediateTypeArgs);
-      return typeArgs == null || listEquals(typeArgs, other.typeArgs);
+      return typeArgs == null || listEquals(typeArgs!, other.typeArgs!);
     }
     return false;
   }
@@ -1139,7 +1135,7 @@
         : "${nodeToText(_type)}";
     final typeArgsStrs = (numImmediateTypeArgs == 0)
         ? ""
-        : "<${typeArgs.take(numImmediateTypeArgs).map((t) => "$t").join(", ")}>";
+        : "<${typeArgs!.take(numImmediateTypeArgs).map((t) => "$t").join(", ")}>";
     final nullability = _type.nullability.suffix;
     return "$head$typeArgsStrs$nullability";
   }
@@ -1200,15 +1196,15 @@
       if (_type is InterfaceType) {
         Class thisClass = (_type as InterfaceType).classNode;
         if (thisClass == typeHierarchy.coreTypes.futureClass) {
-          return typeArgs[0].isSubtypeOfRuntimeType(
-              typeHierarchy, runtimeType.typeArgs[0], SubtypeTestKind.Subtype);
+          return typeArgs![0].isSubtypeOfRuntimeType(
+              typeHierarchy, runtimeType.typeArgs![0], SubtypeTestKind.Subtype);
         } else {
           return isSubtypeOfRuntimeType(
-              typeHierarchy, runtimeType.typeArgs[0], SubtypeTestKind.Subtype);
+              typeHierarchy, runtimeType.typeArgs![0], SubtypeTestKind.Subtype);
         }
       } else if (_type is FutureOrType) {
-        return typeArgs[0].isSubtypeOfRuntimeType(
-            typeHierarchy, runtimeType.typeArgs[0], SubtypeTestKind.Subtype);
+        return typeArgs![0].isSubtypeOfRuntimeType(
+            typeHierarchy, runtimeType.typeArgs![0], SubtypeTestKind.Subtype);
       }
     }
 
@@ -1236,7 +1232,7 @@
       return true;
     }
 
-    List<Type> usableTypeArgs = typeArgs;
+    List<Type>? usableTypeArgs = typeArgs;
     if (usableTypeArgs == null) {
       assert(thisClass.typeParameters.isEmpty);
       usableTypeArgs =
@@ -1248,7 +1244,7 @@
         runtimeType.numImmediateTypeArgs);
     for (int i = 0; i < runtimeType.numImmediateTypeArgs; ++i) {
       if (!usableTypeArgs[interfaceOffset + i].isSubtypeOfRuntimeType(
-          typeHierarchy, runtimeType.typeArgs[i], SubtypeTestKind.Subtype)) {
+          typeHierarchy, runtimeType.typeArgs![i], SubtypeTestKind.Subtype)) {
         return false;
       }
     }
diff --git a/pkg/vm/lib/transformations/type_flow/unboxing_info.dart b/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
index 723e673..682cf58 100644
--- a/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
+++ b/pkg/vm/lib/transformations/type_flow/unboxing_info.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
-
 import 'package:kernel/ast.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/external_name.dart' show getExternalName;
@@ -30,12 +28,12 @@
         _coreTypes = typeFlowAnalysis.environment.coreTypes,
         _nativeCodeOracle = typeFlowAnalysis.nativeCodeOracle;
 
-  UnboxingInfoMetadata getUnboxingInfoOfMember(Member member) {
-    final UnboxingInfoMetadata info = _memberInfo[member];
+  UnboxingInfoMetadata? getUnboxingInfoOfMember(Member member) {
+    final UnboxingInfoMetadata? info = _memberInfo[member];
     if (member is Procedure && member.isGetter) {
       // Remove placeholder parameter info slot for setters that the getter is
       // grouped with.
-      return UnboxingInfoMetadata(0)..returnInfo = info.returnInfo;
+      return UnboxingInfoMetadata(0)..returnInfo = info!.returnInfo;
     }
     return info;
   }
@@ -81,8 +79,8 @@
           ? (member.hasSetter ? 1 : 0)
           : member is Procedure && member.isGetter
               ? 1
-              : member.function.requiredParameterCount;
-      UnboxingInfoMetadata info;
+              : member.function!.requiredParameterCount;
+      UnboxingInfoMetadata? info;
       if (member.isInstanceMember) {
         int selectorId =
             member is Field || member is Procedure && member.isGetter
@@ -121,20 +119,18 @@
   void _updateUnboxingInfoOfMember(
       Member member, TypeFlowAnalysis typeFlowAnalysis) {
     if (typeFlowAnalysis.isMemberUsed(member)) {
-      final UnboxingInfoMetadata unboxingInfo = _memberInfo[member];
+      final UnboxingInfoMetadata unboxingInfo = _memberInfo[member]!;
       if (_cannotUnbox(member)) {
         unboxingInfo.unboxedArgsInfo.length = 0;
         unboxingInfo.returnInfo = UnboxingInfoMetadata.kBoxed;
         return;
       }
       if (member is Procedure || member is Constructor) {
-        final Args<Type> argTypes = typeFlowAnalysis.argumentTypes(member);
-        assert(argTypes != null);
-
+        final Args<Type> argTypes = typeFlowAnalysis.argumentTypes(member)!;
         final int firstParamIndex =
             numTypeParams(member) + (hasReceiverArg(member) ? 1 : 0);
 
-        final positionalParams = member.function.positionalParameters;
+        final positionalParams = member.function!.positionalParameters;
         assert(argTypes.positionalCount ==
             firstParamIndex + positionalParams.length);
 
diff --git a/pkg/vm/lib/transformations/type_flow/utils.dart b/pkg/vm/lib/transformations/type_flow/utils.dart
index b04e69e..c85dfc7 100644
--- a/pkg/vm/lib/transformations/type_flow/utils.dart
+++ b/pkg/vm/lib/transformations/type_flow/utils.dart
@@ -2,12 +2,11 @@
 // 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
-
 /// Declares miscellaneous utility functions and constants for type flow
 /// analysis.
 library vm.transformations.type_flow.utils;
 
+import 'package:collection/collection.dart' show IterableExtension;
 import 'package:kernel/ast.dart';
 import 'package:kernel/src/printer.dart';
 
@@ -123,9 +122,8 @@
   return true;
 }
 
-VariableDeclaration findNamedParameter(FunctionNode function, String name) {
-  return function.namedParameters
-      .firstWhere((p) => p.name == name, orElse: () => null);
+VariableDeclaration? findNamedParameter(FunctionNode function, String name) {
+  return function.namedParameters.firstWhereOrNull((p) => p.name == name);
 }
 
 class Histogram<K> {
@@ -143,7 +141,7 @@
     print(
         '-------------------------------------------------------------------');
     List<K> keys = values.keys.toList();
-    keys.sort((k1, k2) => values[k1].compareTo(values[k2]));
+    keys.sort((k1, k2) => values[k1]!.compareTo(values[k2]!));
     final cut = keys.length < n ? 0 : keys.length - n;
     for (int i = keys.length - 1; i >= cut; --i) {
       final k = keys[i];
@@ -376,7 +374,7 @@
 };
 
 extension NullabilitySuffix on Nullability {
-  String get suffix => nullabilitySuffix[this];
+  String get suffix => nullabilitySuffix[this]!;
 }
 
 bool mayHaveSideEffects(Expression node) {
diff --git a/pkg/vm/pubspec.yaml b/pkg/vm/pubspec.yaml
index f57cf389..0e78a09 100644
--- a/pkg/vm/pubspec.yaml
+++ b/pkg/vm/pubspec.yaml
@@ -18,6 +18,7 @@
   meta:
     path: ../meta
   package_config: any
+  collection: ^1.15.0
 
 dev_dependencies:
   expect:
diff --git a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
index f9ea8d7..2e25344 100644
--- a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
+++ b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
@@ -60,7 +60,7 @@
   void recordMemberCalledViaThis(Member target) {}
 
   @override
-  void recordTearOff(Procedure target) {}
+  void recordTearOff(Member target) {}
 }
 
 class PrintSummaries extends RecursiveVisitor {
@@ -78,7 +78,7 @@
         typesBuilder,
         new NativeCodeOracle(
             null, new ConstantPragmaAnnotationParser(coreTypes)),
-        new GenericInterfacesInfoImpl(hierarchy),
+        new GenericInterfacesInfoImpl(coreTypes, hierarchy),
         /*_protobufHandler=*/ null);
   }