Version 2.18.0-245.0.dev

Merge commit '99919c69ba1f374a8d793bcfe43e2a1702a1b82b' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index d91b11e..fbcedf8 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -387,7 +387,7 @@
       new ExpressionInfo<Variable, Type>(after, ifFalse, ifTrue);
 
   ExpressionInfo<Variable, Type>? rebaseForward(
-          TypeOperations<Variable, Type> typeOperations,
+          TypeOperations<Type> typeOperations,
           FlowModel<Variable, Type> base) =>
       new ExpressionInfo(base, ifTrue.rebaseForward(typeOperations, base),
           ifFalse.rebaseForward(typeOperations, base));
@@ -405,22 +405,22 @@
 /// while visiting the code for type inference.
 abstract class FlowAnalysis<Node extends Object, Statement extends Node,
     Expression extends Object, Variable extends Object, Type extends Object> {
-  factory FlowAnalysis(TypeOperations<Variable, Type> typeOperations,
+  factory FlowAnalysis(Operations<Variable, Type> operations,
       AssignedVariables<Node, Variable> assignedVariables,
       {required bool respectImplicitlyTypedVarInitializers}) {
-    return new _FlowAnalysisImpl(typeOperations, assignedVariables,
+    return new _FlowAnalysisImpl(operations, assignedVariables,
         respectImplicitlyTypedVarInitializers:
             respectImplicitlyTypedVarInitializers);
   }
 
-  factory FlowAnalysis.legacy(TypeOperations<Variable, Type> typeOperations,
+  factory FlowAnalysis.legacy(Operations<Variable, Type> operations,
           AssignedVariables<Node, Variable> assignedVariables) =
       _LegacyTypePromotion;
 
   /// Return `true` if the current state is reachable.
   bool get isReachable;
 
-  TypeOperations<Variable, Type> get typeOperations;
+  TypeOperations<Type> get operations;
 
   /// Call this method after visiting an "as" expression.
   ///
@@ -1040,22 +1040,21 @@
 
   bool _exceptionOccurred = false;
 
-  factory FlowAnalysisDebug(TypeOperations<Variable, Type> typeOperations,
+  factory FlowAnalysisDebug(Operations<Variable, Type> operations,
       AssignedVariables<Node, Variable> assignedVariables,
       {required bool respectImplicitlyTypedVarInitializers}) {
     print('FlowAnalysisDebug()');
     return new FlowAnalysisDebug._(new _FlowAnalysisImpl(
-        typeOperations, assignedVariables,
+        operations, assignedVariables,
         respectImplicitlyTypedVarInitializers:
             respectImplicitlyTypedVarInitializers));
   }
 
-  factory FlowAnalysisDebug.legacy(
-      TypeOperations<Variable, Type> typeOperations,
+  factory FlowAnalysisDebug.legacy(Operations<Variable, Type> operations,
       AssignedVariables<Node, Variable> assignedVariables) {
     print('FlowAnalysisDebug.legacy()');
     return new FlowAnalysisDebug._(
-        new _LegacyTypePromotion(typeOperations, assignedVariables));
+        new _LegacyTypePromotion(operations, assignedVariables));
   }
 
   FlowAnalysisDebug._(this._wrapped);
@@ -1065,7 +1064,7 @@
       _wrap('isReachable', () => _wrapped.isReachable, isQuery: true);
 
   @override
-  TypeOperations<Variable, Type> get typeOperations => _wrapped.typeOperations;
+  TypeOperations<Type> get operations => _wrapped.operations;
 
   @override
   void asExpression_end(Expression subExpression, Type type) {
@@ -1680,7 +1679,7 @@
   /// assignments that occurred during the `try` block, to the extent that they
   /// weren't invalidated by later assignments in the `finally` block.
   FlowModel<Variable, Type> attachFinally(
-      TypeOperations<Variable, Type> typeOperations,
+      TypeOperations<Type> typeOperations,
       FlowModel<Variable, Type> beforeFinally,
       FlowModel<Variable, Type> afterFinally) {
     // Code that follows the `try/finally` is reachable iff the end of the `try`
@@ -1854,8 +1853,7 @@
   /// regardless of the type of loop.
   @visibleForTesting
   FlowModel<Variable, Type> inheritTested(
-      TypeOperations<Variable, Type> typeOperations,
-      FlowModel<Variable, Type> other) {
+      TypeOperations<Type> typeOperations, FlowModel<Variable, Type> other) {
     Map<Variable?, VariableModel<Variable, Type>> newVariableInfo =
         <Variable?, VariableModel<Variable, Type>>{};
     Map<Variable?, VariableModel<Variable, Type>> otherVariableInfo =
@@ -1893,8 +1891,7 @@
   /// will be promoted in the output model, provided that hasn't been reassigned
   /// since then (which would make the promotion unsound).
   FlowModel<Variable, Type> rebaseForward(
-      TypeOperations<Variable, Type> typeOperations,
-      FlowModel<Variable, Type> base) {
+      TypeOperations<Type> typeOperations, FlowModel<Variable, Type> base) {
     // The rebased model is reachable iff both `this` and the new base are
     // reachable.
     Reachability newReachable = reachable.rebaseForward(base.reachable);
@@ -2004,7 +2001,7 @@
   /// Note that the state is only changed if the previous type of [variable] was
   /// potentially nullable.
   ExpressionInfo<Variable, Type> tryMarkNonNullable(
-      TypeOperations<Variable, Type> typeOperations,
+      TypeOperations<Type> typeOperations,
       ReferenceWithType<Variable, Type> referenceWithType) {
     VariableModel<Variable, Type> info =
         referenceWithType.reference.getInfo(variableInfo);
@@ -2038,7 +2035,7 @@
   /// TODO(paulberry): if the type is non-nullable, should this method mark the
   /// variable as definitely assigned?  Does it matter?
   FlowModel<Variable, Type> tryPromoteForTypeCast(
-      TypeOperations<Variable, Type> typeOperations,
+      TypeOperations<Type> typeOperations,
       ReferenceWithType<Variable, Type> referenceWithType,
       Type type) {
     VariableModel<Variable, Type> info =
@@ -2069,7 +2066,7 @@
   /// TODO(paulberry): if the type is non-nullable, should this method mark the
   /// variable as definitely assigned?  Does it matter?
   ExpressionInfo<Variable, Type> tryPromoteForTypeCheck(
-      TypeOperations<Variable, Type> typeOperations,
+      TypeOperations<Type> typeOperations,
       ReferenceWithType<Variable, Type> referenceWithType,
       Type type) {
     VariableModel<Variable, Type> info =
@@ -2136,13 +2133,13 @@
       Variable variable,
       Type writtenType,
       SsaNode<Variable, Type> newSsaNode,
-      TypeOperations<Variable, Type> typeOperations,
+      Operations<Variable, Type> operations,
       {bool promoteToTypeOfInterest = true}) {
     VariableModel<Variable, Type>? infoForVar = variableInfo[variable];
     if (infoForVar == null) return this;
 
     VariableModel<Variable, Type> newInfoForVar = infoForVar.write(
-        nonPromotionReason, variable, writtenType, typeOperations, newSsaNode,
+        nonPromotionReason, variable, writtenType, operations, newSsaNode,
         promoteToTypeOfInterest: promoteToTypeOfInterest);
     if (identical(newInfoForVar, infoForVar)) return this;
 
@@ -2161,7 +2158,7 @@
   ///   no redundant or side-promotions)
   /// - The variable should not be write-captured.
   FlowModel<Variable, Type> _finishTypeTest(
-    TypeOperations<Variable, Type> typeOperations,
+    TypeOperations<Type> typeOperations,
     Reference<Variable, Type> reference,
     VariableModel<Variable, Type> info,
     Type? testedType,
@@ -2223,7 +2220,7 @@
   /// less specific type promotion is kept.
   static FlowModel<Variable, Type>
       join<Variable extends Object, Type extends Object>(
-    TypeOperations<Variable, Type> typeOperations,
+    TypeOperations<Type> typeOperations,
     FlowModel<Variable, Type>? first,
     FlowModel<Variable, Type>? second,
     Map<Variable?, VariableModel<Variable, Type>> emptyVariableMap,
@@ -2255,7 +2252,7 @@
   @visibleForTesting
   static Map<Variable?, VariableModel<Variable, Type>>
       joinVariableInfo<Variable extends Object, Type extends Object>(
-    TypeOperations<Variable, Type> typeOperations,
+    TypeOperations<Type> typeOperations,
     Map<Variable?, VariableModel<Variable, Type>> first,
     Map<Variable?, VariableModel<Variable, Type>> second,
     Map<Variable?, VariableModel<Variable, Type>> emptyMap,
@@ -2295,7 +2292,7 @@
   /// merge of two control flow paths.
   static FlowModel<Variable, Type>
       merge<Variable extends Object, Type extends Object>(
-    TypeOperations<Variable, Type> typeOperations,
+    TypeOperations<Type> typeOperations,
     FlowModel<Variable, Type>? first,
     FlowModel<Variable, Type>? second,
     Map<Variable?, VariableModel<Variable, Type>> emptyVariableMap,
@@ -2424,6 +2421,11 @@
   R visitThisNotPromoted(ThisNotPromoted reason);
 }
 
+/// Operations on types and variables, abstracted from concrete type interfaces.
+abstract class Operations<Variable extends Object, Type extends Object>
+    extends TypeOperations<Type> implements VariableOperations<Variable, Type> {
+}
+
 /// Non-promotion reason describing the situation where an expression was not
 /// promoted due to the fact that it's a property get.
 class PropertyNotPromoted<Type extends Object> extends NonPromotionReason {
@@ -2614,7 +2616,7 @@
   Map<Type, NonPromotionReason> Function() getNonPromotionReasons(
       Map<Variable?, VariableModel<Variable, Type>> variableInfo,
       Type staticType,
-      TypeOperations<Variable, Type> typeOperations);
+      Operations<Variable, Type> operations);
 
   /// Creates a reference representing a get of a property called [propertyName]
   /// on the reference represented by `this`.
@@ -2711,7 +2713,7 @@
 }
 
 /// Operations on types, abstracted from concrete type interfaces.
-abstract class TypeOperations<Variable extends Object, Type extends Object> {
+abstract class TypeOperations<Type extends Object> {
   /// Classifies the given type into one of the three categories defined by
   /// the [TypeClassification] enum.
   TypeClassification classifyType(Type type);
@@ -2765,9 +2767,6 @@
   /// Tries to promote to the first type from the second type, and returns the
   /// promoted type if it succeeds, otherwise null.
   Type? tryPromoteToType(Type to, Type from);
-
-  /// Return the static type of the given [variable].
-  Type variableType(Variable variable);
 }
 
 /// An instance of the [VariableModel] class represents the information gathered
@@ -2905,7 +2904,7 @@
       NonPromotionReason? nonPromotionReason,
       Variable variable,
       Type writtenType,
-      TypeOperations<Variable, Type> typeOperations,
+      Operations<Variable, Type> operations,
       SsaNode<Variable, Type> newSsaNode,
       {required bool promoteToTypeOfInterest}) {
     if (writeCaptured) {
@@ -2918,13 +2917,13 @@
     }
 
     _DemotionResult<Type> demotionResult =
-        _demoteViaAssignment(writtenType, typeOperations, nonPromotionReason);
+        _demoteViaAssignment(writtenType, operations, nonPromotionReason);
     List<Type>? newPromotedTypes = demotionResult.promotedTypes;
 
-    Type declaredType = typeOperations.variableType(variable);
+    Type declaredType = operations.variableType(variable);
     if (promoteToTypeOfInterest) {
       newPromotedTypes = _tryPromoteToTypeOfInterest(
-          typeOperations, declaredType, newPromotedTypes, writtenType);
+          operations, declaredType, newPromotedTypes, writtenType);
     }
     // TODO(paulberry): remove demotions from demotionResult.nonPromotionHistory
     // that are no longer in effect due to re-promotion.
@@ -2972,7 +2971,7 @@
   /// describing the reason for the potential demotion.
   _DemotionResult<Type> _demoteViaAssignment(
       Type writtenType,
-      TypeOperations<Variable, Type> typeOperations,
+      TypeOperations<Type> typeOperations,
       NonPromotionReason? nonPromotionReason) {
     List<Type>? promotedTypes = this.promotedTypes;
     if (promotedTypes == null) {
@@ -3012,11 +3011,8 @@
   ///
   /// Note that since promotion chains are considered immutable, if promotion
   /// is required, a new promotion chain will be created and returned.
-  List<Type>? _tryPromoteToTypeOfInterest(
-      TypeOperations<Variable, Type> typeOperations,
-      Type declaredType,
-      List<Type>? promotedTypes,
-      Type writtenType) {
+  List<Type>? _tryPromoteToTypeOfInterest(TypeOperations<Type> typeOperations,
+      Type declaredType, List<Type>? promotedTypes, Type writtenType) {
     assert(!writeCaptured);
 
     if (typeOperations.forcePromotion(
@@ -3129,7 +3125,7 @@
   @visibleForTesting
   static VariableModel<Variable, Type>
       inheritTested<Variable extends Object, Type extends Object>(
-          TypeOperations<Variable, Type> typeOperations,
+          TypeOperations<Type> typeOperations,
           VariableModel<Variable, Type> model,
           List<Type> tested) {
     List<Type> newTested = joinTested(tested, model.tested, typeOperations);
@@ -3145,7 +3141,7 @@
   /// Joins two variable models.  See [FlowModel.join] for details.
   static VariableModel<Variable, Type>
       join<Variable extends Object, Type extends Object>(
-          TypeOperations<Variable, Type> typeOperations,
+          TypeOperations<Type> typeOperations,
           VariableModel<Variable, Type> first,
           VariableModel<Variable, Type> second) {
     List<Type>? newPromotedTypes = joinPromotedTypes(
@@ -3175,7 +3171,7 @@
       joinPromotedTypes<Variable extends Object, Type extends Object>(
           List<Type>? chain1,
           List<Type>? chain2,
-          TypeOperations<Variable, Type> typeOperations) {
+          TypeOperations<Type> typeOperations) {
     if (chain1 == null) return chain1;
     if (chain2 == null) return chain2;
 
@@ -3221,7 +3217,7 @@
   static List<Type> joinTested<Variable extends Object, Type extends Object>(
       List<Type> types1,
       List<Type> types2,
-      TypeOperations<Variable, Type> typeOperations) {
+      TypeOperations<Type> typeOperations) {
     // Ensure that types1 is the shorter list.
     if (types1.length > types2.length) {
       List<Type> tmp = types1;
@@ -3259,7 +3255,7 @@
   /// [thisPromotedTypes] or [basePromotedTypes] (to make it easier for the
   /// caller to detect when data structures may be re-used).
   static List<Type>? rebasePromotedTypes<Type extends Object>(
-      TypeOperations<Object, Type> typeOperations,
+      TypeOperations<Type> typeOperations,
       List<Type>? thisPromotedTypes,
       List<Type>? basePromotedTypes) {
     if (basePromotedTypes == null) {
@@ -3297,9 +3293,7 @@
 
   static List<Type>
       _addTypeToUniqueList<Variable extends Object, Type extends Object>(
-          List<Type> types,
-          Type newType,
-          TypeOperations<Variable, Type> typeOperations) {
+          List<Type> types, Type newType, TypeOperations<Type> typeOperations) {
     if (_typeListContains(typeOperations, types, newType)) return types;
     return new List<Type>.of(types)..add(newType);
   }
@@ -3338,9 +3332,7 @@
   }
 
   static bool _typeListContains<Variable extends Object, Type extends Object>(
-      TypeOperations<Variable, Type> typeOperations,
-      List<Type> list,
-      Type searchType) {
+      TypeOperations<Type> typeOperations, List<Type> list, Type searchType) {
     for (Type type in list) {
       if (typeOperations.isSameType(type, searchType)) return true;
     }
@@ -3348,6 +3340,13 @@
   }
 }
 
+/// Operations on variables, abstracted from concrete type interfaces.
+abstract class VariableOperations<Variable extends Object,
+    Type extends Object> {
+  /// Returns the static type of the given [variable].
+  Type variableType(Variable variable);
+}
+
 /// Specialization of [Reference] representing a reference to a local variable
 /// (or function parameter).
 @visibleForTesting
@@ -3362,7 +3361,7 @@
   Map<Type, NonPromotionReason> Function() getNonPromotionReasons(
       Map<Variable?, VariableModel<Variable, Type>> variableInfo,
       Type staticType,
-      TypeOperations<Variable, Type> typeOperations) {
+      Operations<Variable, Type> operations) {
     VariableModel<Variable, Type>? currentVariableInfo = variableInfo[variable];
     if (currentVariableInfo == null) {
       return () => {};
@@ -3370,12 +3369,12 @@
     return () {
       Map<Type, NonPromotionReason> result = <Type, NonPromotionReason>{};
       Type currentType = currentVariableInfo.promotedTypes?.last ??
-          typeOperations.variableType(variable);
+          operations.variableType(variable);
       NonPromotionHistory? nonPromotionHistory =
           currentVariableInfo.nonPromotionHistory;
       while (nonPromotionHistory != null) {
         Type nonPromotedType = nonPromotionHistory.type;
-        if (!typeOperations.isSubtypeOf(currentType, nonPromotedType)) {
+        if (!operations.isSubtypeOf(currentType, nonPromotedType)) {
           result[nonPromotedType] ??= nonPromotionHistory.nonPromotionReason;
         }
         nonPromotionHistory = nonPromotionHistory.previous;
@@ -3483,9 +3482,10 @@
 class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
         Expression extends Object, Variable extends Object, Type extends Object>
     implements FlowAnalysis<Node, Statement, Expression, Variable, Type> {
-  /// The [TypeOperations], used to access types, and check subtyping.
+  /// The [Operations], used to access types, check subtyping, and query
+  /// variable types.
   @override
-  final TypeOperations<Variable, Type> typeOperations;
+  final Operations<Variable, Type> operations;
 
   /// Stack of [_FlowContext] objects representing the statements and
   /// expressions that are currently being visited.
@@ -3526,7 +3526,7 @@
   /// analyzing old language versions).
   final bool respectImplicitlyTypedVarInitializers;
 
-  _FlowAnalysisImpl(this.typeOperations, this._assignedVariables,
+  _FlowAnalysisImpl(this.operations, this._assignedVariables,
       {required this.respectImplicitlyTypedVarInitializers}) {
     if (!_assignedVariables._isFinished) {
       _assignedVariables.finish();
@@ -3551,7 +3551,7 @@
         _getExpressionReference(subExpression);
     if (referenceWithType == null) return;
     _current =
-        _current.tryPromoteForTypeCast(typeOperations, referenceWithType, type);
+        _current.tryPromoteForTypeCast(operations, referenceWithType, type);
   }
 
   @override
@@ -3673,9 +3673,9 @@
     ReferenceWithType<Variable, Type>? rhsReference =
         rightOperandInfo!._reference;
     TypeClassification leftOperandTypeClassification =
-        typeOperations.classifyType(leftOperandInfo._type);
+        operations.classifyType(leftOperandInfo._type);
     TypeClassification rightOperandTypeClassification =
-        typeOperations.classifyType(rightOperandInfo._type);
+        operations.classifyType(rightOperandInfo._type);
     if (leftOperandTypeClassification == TypeClassification.nullOrEquivalent &&
         rightOperandTypeClassification == TypeClassification.nullOrEquivalent) {
       booleanLiteral(wholeExpression, !notEqual);
@@ -3692,13 +3692,13 @@
     } else if (leftOperandInfo._expressionInfo is _NullInfo<Variable, Type> &&
         rhsReference != null) {
       ExpressionInfo<Variable, Type> equalityInfo =
-          _current.tryMarkNonNullable(typeOperations, rhsReference);
+          _current.tryMarkNonNullable(operations, rhsReference);
       _storeExpressionInfo(
           wholeExpression, notEqual ? equalityInfo : equalityInfo.invert());
     } else if (rightOperandInfo._expressionInfo is _NullInfo<Variable, Type> &&
         lhsReference != null) {
       ExpressionInfo<Variable, Type> equalityInfo =
-          _current.tryMarkNonNullable(typeOperations, lhsReference);
+          _current.tryMarkNonNullable(operations, lhsReference);
       _storeExpressionInfo(
           wholeExpression, notEqual ? equalityInfo : equalityInfo.invert());
     }
@@ -3743,8 +3743,8 @@
     FlowModel<Variable, Type>? breakState = context._breakModel;
     FlowModel<Variable, Type> falseCondition = context._conditionInfo.ifFalse;
 
-    _current = _merge(falseCondition, breakState)
-        .inheritTested(typeOperations, _current);
+    _current =
+        _merge(falseCondition, breakState).inheritTested(operations, _current);
   }
 
   @override
@@ -3840,7 +3840,7 @@
     _current = _current.split();
     if (lhsReference != null) {
       ExpressionInfo<Variable, Type> promotionInfo =
-          _current.tryMarkNonNullable(typeOperations, lhsReference);
+          _current.tryMarkNonNullable(operations, lhsReference);
       _current = promotionInfo.ifFalse;
       promoted = promotionInfo.ifTrue;
     } else {
@@ -3906,17 +3906,15 @@
     SsaNode<Variable, Type> newSsaNode = new SsaNode<Variable, Type>(
         expressionInfo is _TrivialExpressionInfo ? null : expressionInfo);
     _current = _current.write(
-        null, variable, initializerType, newSsaNode, typeOperations,
+        null, variable, initializerType, newSsaNode, operations,
         promoteToTypeOfInterest: !isImplicitlyTyped && !isFinal);
-    if (isImplicitlyTyped &&
-        typeOperations.isTypeParameterType(initializerType)) {
+    if (isImplicitlyTyped && operations.isTypeParameterType(initializerType)) {
       _current = _current
           .tryPromoteForTypeCheck(
-              typeOperations,
+              operations,
               new ReferenceWithType<Variable, Type>(
                   new VariableReference<Variable, Type>(variable),
-                  promotedType(variable) ??
-                      typeOperations.variableType(variable)),
+                  promotedType(variable) ?? operations.variableType(variable)),
               initializerType)
           .ifTrue;
     }
@@ -3934,7 +3932,7 @@
         _getExpressionReference(subExpression);
     if (subExpressionReference != null) {
       ExpressionInfo<Variable, Type> expressionInfo = _current
-          .tryPromoteForTypeCheck(typeOperations, subExpressionReference, type);
+          .tryPromoteForTypeCheck(operations, subExpressionReference, type);
       _storeExpressionInfo(
           isExpression, isNot ? expressionInfo.invert() : expressionInfo);
     }
@@ -4028,7 +4026,7 @@
         _getExpressionReference(operand);
     if (operandReference != null) {
       _current =
-          _current.tryMarkNonNullable(typeOperations, operandReference).ifTrue;
+          _current.tryMarkNonNullable(operations, operandReference).ifTrue;
     }
   }
 
@@ -4049,7 +4047,7 @@
         _getExpressionReference(target);
     if (targetReference != null) {
       _current =
-          _current.tryMarkNonNullable(typeOperations, targetReference).ifTrue;
+          _current.tryMarkNonNullable(operations, targetReference).ifTrue;
     }
   }
 
@@ -4207,7 +4205,7 @@
     _TryFinallyContext<Variable, Type> context =
         _stack.removeLast() as _TryFinallyContext<Variable, Type>;
     _current = context._afterBodyAndCatches!
-        .attachFinally(typeOperations, context._beforeFinally, _current);
+        .attachFinally(operations, context._beforeFinally, _current);
   }
 
   @override
@@ -4229,12 +4227,12 @@
     VariableModel<Variable, Type> variableModel =
         variableReference.getInfo(_current.variableInfo);
     Type? promotedType = variableModel.promotedTypes?.last;
-    Type currentType = promotedType ?? typeOperations.variableType(variable);
+    Type currentType = promotedType ?? operations.variableType(variable);
     _storeExpressionReference(expression,
         new ReferenceWithType<Variable, Type>(variableReference, currentType));
     ExpressionInfo<Variable, Type>? expressionInfo = variableModel
         .ssaNode?.expressionInfo
-        ?.rebaseForward(typeOperations, _current);
+        ?.rebaseForward(operations, _current);
     if (expressionInfo != null) {
       _storeExpressionInfo(expression, expressionInfo);
     }
@@ -4265,7 +4263,7 @@
     _WhileContext<Variable, Type> context =
         _stack.removeLast() as _WhileContext<Variable, Type>;
     _current = _merge(context._conditionInfo.ifFalse, context._breakModel)
-        .inheritTested(typeOperations, _current);
+        .inheritTested(operations, _current);
   }
 
   @override
@@ -4275,7 +4273,7 @@
           _expressionReference;
       if (referenceWithType != null) {
         return referenceWithType.reference.getNonPromotionReasons(
-            _current.variableInfo, referenceWithType.type, typeOperations);
+            _current.variableInfo, referenceWithType.type, operations);
       }
     }
     return () => {};
@@ -4284,8 +4282,8 @@
   @override
   Map<Type, NonPromotionReason> Function() whyNotPromotedImplicitThis(
       Type staticType) {
-    return new _ThisReference<Variable, Type>().getNonPromotionReasons(
-        _current.variableInfo, staticType, typeOperations);
+    return new _ThisReference<Variable, Type>()
+        .getNonPromotionReasons(_current.variableInfo, staticType, operations);
   }
 
   @override
@@ -4301,7 +4299,7 @@
         variable,
         writtenType,
         newSsaNode,
-        typeOperations);
+        operations);
   }
 
   @override
@@ -4355,12 +4353,11 @@
 
   FlowModel<Variable, Type> _join(FlowModel<Variable, Type>? first,
           FlowModel<Variable, Type>? second) =>
-      FlowModel.join(typeOperations, first, second, _current._emptyVariableMap);
+      FlowModel.join(operations, first, second, _current._emptyVariableMap);
 
   FlowModel<Variable, Type> _merge(
           FlowModel<Variable, Type> first, FlowModel<Variable, Type>? second) =>
-      FlowModel.merge(
-          typeOperations, first, second, _current._emptyVariableMap);
+      FlowModel.merge(operations, first, second, _current._emptyVariableMap);
 
   /// Associates [expression], which should be the most recently visited
   /// expression, with the given [expressionInfo] object, and updates the
@@ -4462,8 +4459,9 @@
 class _LegacyTypePromotion<Node extends Object, Statement extends Node,
         Expression extends Object, Variable extends Object, Type extends Object>
     implements FlowAnalysis<Node, Statement, Expression, Variable, Type> {
-  /// The [TypeOperations], used to access types, and check subtyping.
-  final TypeOperations<Variable, Type> _typeOperations;
+  /// The [Operations], used to access types, check subtyping, and query
+  /// variable types.
+  final Operations<Variable, Type> _operations;
 
   /// Information about variable assignments computed during the previous
   /// compilation pass.
@@ -4493,13 +4491,13 @@
   /// written to during the LHS of the "and".
   final List<Set<Variable>> _writeStackForAnd = [{}];
 
-  _LegacyTypePromotion(this._typeOperations, this._assignedVariables);
+  _LegacyTypePromotion(this._operations, this._assignedVariables);
 
   @override
   bool get isReachable => true;
 
   @override
-  TypeOperations<Variable, Type> get typeOperations => _typeOperations;
+  TypeOperations<Type> get operations => _operations;
 
   @override
   void asExpression_end(Expression subExpression, Type type) {}
@@ -4655,10 +4653,10 @@
     if (!isNot && expressionInfo is _LegacyVariableReadInfo<Variable, Type>) {
       Variable variable = expressionInfo._variable;
       Type currentType =
-          _knownTypes[variable] ?? _typeOperations.variableType(variable);
-      Type? promotedType = _typeOperations.tryPromoteToType(type, currentType);
+          _knownTypes[variable] ?? _operations.variableType(variable);
+      Type? promotedType = _operations.tryPromoteToType(type, currentType);
       if (promotedType != null &&
-          !_typeOperations.isSameType(currentType, promotedType)) {
+          !_operations.isSameType(currentType, promotedType)) {
         _storeExpressionInfo(
             isExpression,
             new _LegacyExpressionInfo<Variable, Type>(
@@ -4729,9 +4727,9 @@
         newShownTypes[entry.key] = entry.value;
       } else {
         Type? newShownType =
-            _typeOperations.tryPromoteToType(entry.value, previouslyShownType);
+            _operations.tryPromoteToType(entry.value, previouslyShownType);
         if (newShownType != null &&
-            !_typeOperations.isSameType(previouslyShownType, newShownType)) {
+            !_operations.isSameType(previouslyShownType, newShownType)) {
           newShownTypes[entry.key] = newShownType;
         }
       }
@@ -5008,7 +5006,7 @@
 
   @override
   ExpressionInfo<Variable, Type>? rebaseForward(
-          TypeOperations<Variable, Type> typeOperations,
+          TypeOperations<Type> typeOperations,
           FlowModel<Variable, Type> base) =>
       null;
 }
@@ -5035,7 +5033,7 @@
   Map<Type, NonPromotionReason> Function() getNonPromotionReasons(
       Map<Variable?, VariableModel<Variable, Type>> variableInfo,
       Type staticType,
-      TypeOperations<Variable, Type> typeOperations) {
+      TypeOperations<Type> typeOperations) {
     List<Type>? promotedTypes = _getInfo(variableInfo)?.promotedTypes;
     if (promotedTypes != null) {
       return () {
@@ -5114,7 +5112,7 @@
   Map<Type, NonPromotionReason> Function() getNonPromotionReasons(
       Map<Variable?, VariableModel<Variable, Type>> variableInfo,
       Type staticType,
-      TypeOperations<Variable, Type> typeOperations) {
+      TypeOperations<Type> typeOperations) {
     List<Type>? promotedTypes = _getInfo(variableInfo)?.promotedTypes;
     if (promotedTypes != null) {
       return () {
@@ -5161,7 +5159,7 @@
 
   @override
   ExpressionInfo<Variable, Type> rebaseForward(
-          TypeOperations<Variable, Type> typeOperations,
+          TypeOperations<Type> typeOperations,
           FlowModel<Variable, Type> base) =>
       new _TrivialExpressionInfo(base);
 }
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index 3a8528c..2267aaa 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -247,9 +247,9 @@
 }
 
 /// Test harness for creating flow analysis tests.  This class implements all
-/// the [TypeOperations] needed by flow analysis, as well as other methods
-/// needed for testing.
-class Harness extends TypeOperations<Var, Type> {
+/// the [Operations] needed by flow analysis, as well as other methods needed
+/// for testing.
+class Harness extends Operations<Var, Type> {
   static const Map<String, bool> _coreSubtypes = const {
     'bool <: int': false,
     'bool <: Object': true,
@@ -1486,7 +1486,7 @@
     var rightType = analyzeExpression(rhs);
     flow.ifNullExpression_end();
     return leastUpperBound(
-        flow.typeOperations.promoteToNonNull(leftType), rightType);
+        flow.operations.promoteToNonNull(leftType), rightType);
   }
 
   void analyzeIfStatement(Statement node, Expression condition,
@@ -1520,7 +1520,7 @@
   Type analyzeNonNullAssert(Expression node, Expression expression) {
     var type = analyzeExpression(expression);
     flow.nonNullAssert_end(expression);
-    return flow.typeOperations.promoteToNonNull(type);
+    return flow.operations.promoteToNonNull(type);
   }
 
   Type analyzeNullLiteral(Expression node) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 4b31179..7b8101e 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -59,7 +59,7 @@
 /// be extracted.
 class FlowAnalysisHelper {
   /// The reused instance for creating new [FlowAnalysis] instances.
-  final TypeSystemTypeOperations _typeOperations;
+  final TypeSystemOperations _typeOperations;
 
   /// Precomputed sets of potentially assigned variables.
   AssignedVariables<AstNode, PromotableElement>? assignedVariables;
@@ -82,7 +82,7 @@
 
   FlowAnalysisHelper(TypeSystemImpl typeSystem, bool retainDataForTesting,
       FeatureSet featureSet)
-      : this._(TypeSystemTypeOperations(typeSystem),
+      : this._(TypeSystemOperations(typeSystem),
             retainDataForTesting ? FlowAnalysisDataForTesting() : null,
             isNonNullableByDefault: featureSet.isEnabled(Feature.non_nullable),
             respectImplicitlyTypedVarInitializers:
@@ -375,11 +375,10 @@
   }
 }
 
-class TypeSystemTypeOperations
-    extends TypeOperations<PromotableElement, DartType> {
+class TypeSystemOperations extends Operations<PromotableElement, DartType> {
   final TypeSystemImpl typeSystem;
 
-  TypeSystemTypeOperations(this.typeSystem);
+  TypeSystemOperations(this.typeSystem);
 
   @override
   TypeClassification classifyType(DartType type) {
diff --git a/pkg/dart2native/lib/dart2native_macho.dart b/pkg/dart2native/lib/dart2native_macho.dart
index 1c45d13..b10133e 100644
--- a/pkg/dart2native/lib/dart2native_macho.dart
+++ b/pkg/dart2native/lib/dart2native_macho.dart
@@ -369,15 +369,20 @@
     // Thus, to sign the binary, the developer must force signature overwriting.
     final signingProcess = await Process.run('codesign', args);
     if (signingProcess.exitCode != 0) {
-      print('Failed to replace the dartaotruntime signature, ');
-      print('subcommand terminated with exit code ${signingProcess.exitCode}.');
+      stderr
+        ..write('Failed to replace the dartaotruntime signature, ')
+        ..write('subcommand terminated with exit code ')
+        ..write(signingProcess.exitCode)
+        ..writeln('.');
       if (signingProcess.stdout.isNotEmpty) {
-        print('Subcommand stdout:');
-        print(signingProcess.stdout);
+        stderr
+          ..writeln('Subcommand stdout:')
+          ..writeln(signingProcess.stdout);
       }
       if (signingProcess.stderr.isNotEmpty) {
-        print('Subcommand stderr:');
-        print(signingProcess.stderr);
+        stderr
+          ..writeln('Subcommand stderr:')
+          ..writeln(signingProcess.stderr);
       }
       throw 'Could not sign the new executable';
     }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index 9a94858..23cc739 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -260,10 +260,10 @@
 }
 
 /// CFE-specific implementation of [TypeOperations].
-class TypeOperationsCfe extends TypeOperations<VariableDeclaration, DartType> {
+class OperationsCfe extends Operations<VariableDeclaration, DartType> {
   final TypeEnvironment typeEnvironment;
 
-  TypeOperationsCfe(this.typeEnvironment);
+  OperationsCfe(this.typeEnvironment);
 
   @override
   TypeClassification classifyType(DartType? type) {
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index fb520a1..68129b6 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -228,16 +228,14 @@
 
   @override
   late final FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration,
-          DartType> flowAnalysis =
-      libraryBuilder.isNonNullableByDefault
-          ? new FlowAnalysis(
-              new TypeOperationsCfe(engine.typeSchemaEnvironment),
-              assignedVariables,
-              respectImplicitlyTypedVarInitializers:
-                  libraryBuilder.libraryFeatures.constructorTearoffs.isEnabled)
-          : new FlowAnalysis.legacy(
-              new TypeOperationsCfe(engine.typeSchemaEnvironment),
-              assignedVariables);
+      DartType> flowAnalysis = libraryBuilder
+          .isNonNullableByDefault
+      ? new FlowAnalysis(
+          new OperationsCfe(engine.typeSchemaEnvironment), assignedVariables,
+          respectImplicitlyTypedVarInitializers:
+              libraryBuilder.libraryFeatures.constructorTearoffs.isEnabled)
+      : new FlowAnalysis.legacy(
+          new OperationsCfe(engine.typeSchemaEnvironment), assignedVariables);
 
   @override
   final AssignedVariables<TreeNode, VariableDeclaration> assignedVariables;
diff --git a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
index a93fa35..69012f6 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
@@ -11,9 +11,9 @@
 import 'package:nnbd_migration/src/nullability_node.dart';
 import 'package:nnbd_migration/src/variables.dart';
 
-/// [TypeOperations] that works with [DecoratedType]s.
+/// [Operations] that works with [DecoratedType]s.
 class DecoratedTypeOperations
-    implements TypeOperations<PromotableElement, DecoratedType> {
+    implements Operations<PromotableElement, DecoratedType> {
   final TypeSystem _typeSystem;
   final Variables? _variableRepository;
   final NullabilityGraph _graph;
diff --git a/runtime/tests/vm/dart/flutter_regress_106510_test.dart b/runtime/tests/vm/dart/flutter_regress_106510_test.dart
new file mode 100644
index 0000000..7c41c20
--- /dev/null
+++ b/runtime/tests/vm/dart/flutter_regress_106510_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--use_slow_path --stress_write_barrier_elimination
+
+// Test that array allocation in noSuchMethod dispatcher is preserving the
+// length register correctly.
+
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+final List<dynamic> list = <dynamic>[];
+
+final List<int> invocations = <int>[];
+
+abstract class B {
+  void someMethod(int v);
+}
+
+class A {
+  noSuchMethod(Invocation i) {
+    Expect.equals(#someMethod, i.memberName);
+    invocations.add(i.positionalArguments[0] as int);
+  }
+}
+
+class C implements B {
+  void someMethod(int v) {
+    invocations.add(v);
+  }
+}
+
+void main() {
+  for (var i = 0; i < 10; i++) {
+    list.add(A());
+    list.add(C());
+  }
+
+  for (var i = 0; i < list.length; i++) {
+    list[i].someMethod(i);
+  }
+
+  Expect.equals(list.length, invocations.length);
+  for (var i = 0; i < list.length; i++) {
+    Expect.equals(i, invocations[i]);
+  }
+}
diff --git a/runtime/tests/vm/dart_2/flutter_regress_106510_test.dart b/runtime/tests/vm/dart_2/flutter_regress_106510_test.dart
new file mode 100644
index 0000000..5139e57
--- /dev/null
+++ b/runtime/tests/vm/dart_2/flutter_regress_106510_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// @dart=2.9
+
+// VMOptions=--use_slow_path --stress_write_barrier_elimination
+
+// Test that array allocation in noSuchMethod dispatcher is preserving the
+// length register correctly.
+
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+final List<dynamic> list = <dynamic>[];
+
+final List<int> invocations = <int>[];
+
+abstract class B {
+  void someMethod(int v);
+}
+
+class A {
+  noSuchMethod(Invocation i) {
+    Expect.equals(#someMethod, i.memberName);
+    invocations.add(i.positionalArguments[0] as int);
+  }
+}
+
+class C implements B {
+  void someMethod(int v) {
+    invocations.add(v);
+  }
+}
+
+void main() {
+  for (var i = 0; i < 10; i++) {
+    list.add(A());
+    list.add(C());
+  }
+
+  for (var i = 0; i < list.length; i++) {
+    list[i].someMethod(i);
+  }
+
+  Expect.equals(list.length, invocations.length);
+  for (var i = 0; i < list.length; i++) {
+    Expect.equals(i, invocations[i]);
+  }
+}
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index fc6b0ea..6f62456 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -46,7 +46,7 @@
   {
     LeafRuntimeScope rt(assembler,
                         /*frame_size=*/0,
-                        /*preserve_registers=*/false);
+                        /*preserve_registers=*/preserve_registers);
     // [R0] already contains first argument.
     __ mov(R1, Operand(THR));
     rt.Call(kEnsureRememberedAndMarkingDeferredRuntimeEntry, 2);
diff --git a/tools/VERSION b/tools/VERSION
index 1525dd4..55034e0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 244
+PRERELEASE 245
 PRERELEASE_PATCH 0
\ No newline at end of file