Version 2.13.0-102.0.dev

Merge commit '810d6c7a6b646d1cda5ffe967b5b99576cfd785d' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 45febc4..3ce1a567e 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
     "constraint, update this by running tools/generate_package_config.dart."
   ],
   "configVersion": 2,
-  "generated": "2021-03-01T09:26:17.118461",
+  "generated": "2021-03-03T09:46:04.757962",
   "generator": "tools/generate_package_config.dart",
   "packages": [
     {
@@ -232,7 +232,7 @@
       "name": "dartdoc",
       "rootUri": "../third_party/pkg/dartdoc",
       "packageUri": "lib/",
-      "languageVersion": "2.10"
+      "languageVersion": "2.11"
     },
     {
       "name": "dds",
@@ -392,7 +392,7 @@
       "name": "linter",
       "rootUri": "../third_party/pkg/linter",
       "packageUri": "lib/",
-      "languageVersion": "2.6"
+      "languageVersion": "2.12"
     },
     {
       "name": "logging",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3f33539..6a2ee87 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,15 @@
 
 #### Dartanalyzer
 
+#### Linter
+
+Updated the Linter to `1.0.0`, which includes:
+
+- full library migration to null-safety.
+- new lint: `use_if_null_to_convert_nulls_to_bools`.
+- new lint: `deprecated_consistency`.
+- new lint: `use_named_constants`.
+- deprecation of `avoid_as`.
 
 ## 2.12.0
 
diff --git a/DEPS b/DEPS
index 383b118..c5853e5 100644
--- a/DEPS
+++ b/DEPS
@@ -118,7 +118,7 @@
   "intl_tag": "0.17.0-nullsafety",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_rev": "b8dfe403fd8528fd14399dee3a6527b55802dd4d",
-  "linter_tag": "0.1.129",
+  "linter_tag": "1.0.0",
   "logging_rev": "e2f633b543ef89c54688554b15ca3d7e425b86a2",
   "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
   "markdown_rev": "9c4beaac96d8f008078e00b027915f81b665d2de",
diff --git a/pkg/_fe_analyzer_shared/lib/src/base/errors.dart b/pkg/_fe_analyzer_shared/lib/src/base/errors.dart
index 46bc443..27bd02b 100644
--- a/pkg/_fe_analyzer_shared/lib/src/base/errors.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/base/errors.dart
@@ -47,7 +47,7 @@
     required String message,
     required this.name,
     required this.uniqueName,
-  })  : _correction = correction,
+  })   : _correction = correction,
         _message = message,
         // ignore: unnecessary_null_comparison
         assert(hasPublishedDocs != null),
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 2f8d1e5..766b57a 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
@@ -321,8 +321,9 @@
 
   @override
   R accept<R, Node extends Object, Expression extends Object,
-              Variable extends Object>(
-          NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor) =>
+              Variable extends Object, Type extends Object>(
+          NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
+              visitor) =>
       visitor.visitDemoteViaExplicitWrite(
           this as DemoteViaExplicitWrite<Variable, Expression>);
 
@@ -348,8 +349,9 @@
 
   @override
   R accept<R, Node extends Object, Expression extends Object,
-              Variable extends Object>(
-          NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor) =>
+              Variable extends Object, Type extends Object>(
+          NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
+              visitor) =>
       visitor.visitDemoteViaForEachVariableWrite(
           this as DemoteViaForEachVariableWrite<Variable, Node>);
 
@@ -766,9 +768,10 @@
   /// Call this method just after visiting a property get expression.
   /// [wholeExpression] should be the whole property get, [target] should be the
   /// expression to the left hand side of the `.`, and [propertyName] should be
-  /// the identifier to the right hand side of the `.`.
-  void propertyGet(
-      Expression wholeExpression, Expression target, String propertyName);
+  /// the identifier to the right hand side of the `.`.  [staticType] should be
+  /// the static type of the value returned by the property get.
+  void propertyGet(Expression wholeExpression, Expression target,
+      String propertyName, Type staticType);
 
   /// Retrieves the SSA node associated with [variable], or `null` if [variable]
   /// is not associated with an SSA node because it is write captured.  For
@@ -808,16 +811,19 @@
   /// Call this method just after visiting the expression `this` (or the
   /// pseudo-expression `super`, in the case of the analyzer, which represents
   /// `super.x` as a property get whose target is `super`).  [expression] should
-  /// be the `this` or `super` expression.
-  void thisOrSuper(Expression expression);
+  /// be the `this` or `super` expression.  [staticType] should be the static
+  /// type of `this`.
+  void thisOrSuper(Expression expression, Type staticType);
 
   /// Call this method just after visiting an expression that represents a
   /// property get on `this` or `super`.  This handles situations where there is
   /// an implicit reference to `this`, or the case of the front end, where
   /// `super.x` is represented by a single expression.  [expression] should be
   /// the whole property get, and [propertyName] should be the name of the
-  /// property being read.
-  void thisOrSuperPropertyGet(Expression expression, String propertyName);
+  /// property being read.  [staticType] should be the static type of the value
+  /// returned by the property get.
+  void thisOrSuperPropertyGet(
+      Expression expression, String propertyName, Type staticType);
 
   /// Call this method just before visiting the body of a "try/catch" statement.
   ///
@@ -928,7 +934,19 @@
   /// promotion, to retrieve information about why [target] was not promoted.
   /// This call must be made right after visiting [target].
   ///
-  /// If [target] is `null` it is assumed to be an implicit reference to `this`.
+  /// The returned value is a map whose keys are types that the user might have
+  /// been expecting the target to be promoted to, and whose values are reasons
+  /// why the corresponding promotion did not occur.  The caller is expected to
+  /// select which non-promotion reason to report to the user by seeing which
+  /// promotion would have prevented the error.  (For example, if an error
+  /// occurs due to the target having a nullable type, the caller should report
+  /// a non-promotion reason associated with non-promotion to a non-nullable
+  /// type).
+  Map<Type, NonPromotionReason> whyNotPromoted(Expression target);
+
+  /// Call this method when an error occurs that may be due to a lack of type
+  /// promotion, to retrieve information about why an implicit reference to
+  /// `this` was not promoted.  [staticType] is the (unpromoted) type of `this`.
   ///
   /// The returned value is a map whose keys are types that the user might have
   /// been expecting the target to be promoted to, and whose values are reasons
@@ -938,7 +956,7 @@
   /// occurs due to the target having a nullable type, the caller should report
   /// a non-promotion reason associated with non-promotion to a non-nullable
   /// type).
-  Map<Type, NonPromotionReason> whyNotPromoted(Expression? target);
+  Map<Type, NonPromotionReason> whyNotPromotedImplicitThis(Type staticType);
 
   /// Register write of the given [variable] in the current state.
   /// [writtenType] should be the type of the value that was written.
@@ -1333,10 +1351,12 @@
   }
 
   @override
-  void propertyGet(
-      Expression wholeExpression, Expression target, String propertyName) {
-    _wrap('propertyGet($wholeExpression, $target, $propertyName)',
-        () => _wrapped.propertyGet(wholeExpression, target, propertyName));
+  void propertyGet(Expression wholeExpression, Expression target,
+      String propertyName, Type staticType) {
+    _wrap(
+        'propertyGet($wholeExpression, $target, $propertyName, $staticType)',
+        () => _wrapped.propertyGet(
+            wholeExpression, target, propertyName, staticType));
   }
 
   @override
@@ -1365,15 +1385,18 @@
   }
 
   @override
-  void thisOrSuper(Expression expression) {
-    return _wrap(
-        'thisOrSuper($expression)', () => _wrapped.thisOrSuper(expression));
+  void thisOrSuper(Expression expression, Type staticType) {
+    return _wrap('thisOrSuper($expression, $staticType)',
+        () => _wrapped.thisOrSuper(expression, staticType));
   }
 
   @override
-  void thisOrSuperPropertyGet(Expression expression, String propertyName) {
-    _wrap('thisOrSuperPropertyGet($expression, $propertyName)',
-        () => _wrapped.thisOrSuperPropertyGet(expression, propertyName));
+  void thisOrSuperPropertyGet(
+      Expression expression, String propertyName, Type staticType) {
+    _wrap(
+        'thisOrSuperPropertyGet($expression, $propertyName, $staticType)',
+        () => _wrapped.thisOrSuperPropertyGet(
+            expression, propertyName, staticType));
   }
 
   @override
@@ -1453,13 +1476,20 @@
   }
 
   @override
-  Map<Type, NonPromotionReason> whyNotPromoted(Expression? target) {
+  Map<Type, NonPromotionReason> whyNotPromoted(Expression target) {
     return _wrap(
         'whyNotPromoted($target)', () => _wrapped.whyNotPromoted(target),
         isQuery: true);
   }
 
   @override
+  Map<Type, NonPromotionReason> whyNotPromotedImplicitThis(Type staticType) {
+    return _wrap('whyNotPromotedImplicitThis($staticType)',
+        () => _wrapped.whyNotPromotedImplicitThis(staticType),
+        isQuery: true);
+  }
+
+  @override
   void write(Expression expression, Variable variable, Type writtenType,
       Expression? writtenExpression) {
     _wrap(
@@ -1895,23 +1925,22 @@
   /// potentially nullable.
   ExpressionInfo<Variable, Type> tryMarkNonNullable(
       TypeOperations<Variable, Type> typeOperations,
-      Reference<Variable, Type> reference) {
-    VariableModel<Variable, Type> info = reference.getInfo(variableInfo);
+      ReferenceWithType<Variable, Type> referenceWithType) {
+    VariableModel<Variable, Type> info =
+        referenceWithType.reference.getInfo(variableInfo);
     if (info.writeCaptured) {
       return new _TrivialExpressionInfo<Variable, Type>(this);
     }
 
-    Type? previousType = info.promotedTypes?.last;
-    previousType ??= reference.getDeclaredType(typeOperations);
-
+    Type previousType = referenceWithType.type;
     Type newType = typeOperations.promoteToNonNull(previousType);
     if (typeOperations.isSameType(newType, previousType)) {
       return new _TrivialExpressionInfo<Variable, Type>(this);
     }
     assert(typeOperations.isSubtypeOf(newType, previousType));
 
-    FlowModel<Variable, Type> modelIfSuccessful =
-        _finishTypeTest(typeOperations, reference, info, null, newType);
+    FlowModel<Variable, Type> modelIfSuccessful = _finishTypeTest(
+        typeOperations, referenceWithType.reference, info, null, newType);
 
     FlowModel<Variable, Type> modelIfFailed = this;
 
@@ -1920,7 +1949,8 @@
   }
 
   /// Returns an [ExpressionInfo] indicating the result of casting the given
-  /// [reference] to the given [type], as a consequence of an `as` expression.
+  /// [referenceWithType] to the given [type], as a consequence of an `as`
+  /// expression.
   ///
   /// Note that the state is only changed if [type] is a subtype of the
   /// variable's previous (possibly promoted) type.
@@ -1929,16 +1959,15 @@
   /// variable as definitely assigned?  Does it matter?
   FlowModel<Variable, Type> tryPromoteForTypeCast(
       TypeOperations<Variable, Type> typeOperations,
-      Reference<Variable, Type> reference,
+      ReferenceWithType<Variable, Type> referenceWithType,
       Type type) {
-    VariableModel<Variable, Type> info = reference.getInfo(variableInfo);
+    VariableModel<Variable, Type> info =
+        referenceWithType.reference.getInfo(variableInfo);
     if (info.writeCaptured) {
       return this;
     }
 
-    Type? previousType = info.promotedTypes?.last;
-    previousType ??= reference.getDeclaredType(typeOperations);
-
+    Type previousType = referenceWithType.type;
     Type? newType = typeOperations.tryPromoteToType(type, previousType);
     if (newType == null || typeOperations.isSameType(newType, previousType)) {
       return this;
@@ -1946,7 +1975,8 @@
 
     assert(typeOperations.isSubtypeOf(newType, previousType),
         "Expected $newType to be a subtype of $previousType.");
-    return _finishTypeTest(typeOperations, reference, info, type, newType);
+    return _finishTypeTest(
+        typeOperations, referenceWithType.reference, info, type, newType);
   }
 
   /// Returns an [ExpressionInfo] indicating the result of checking whether the
@@ -1960,24 +1990,23 @@
   /// variable as definitely assigned?  Does it matter?
   ExpressionInfo<Variable, Type> tryPromoteForTypeCheck(
       TypeOperations<Variable, Type> typeOperations,
-      Reference<Variable, Type> reference,
+      ReferenceWithType<Variable, Type> referenceWithType,
       Type type) {
-    VariableModel<Variable, Type> info = reference.getInfo(variableInfo);
+    VariableModel<Variable, Type> info =
+        referenceWithType.reference.getInfo(variableInfo);
     if (info.writeCaptured) {
       return new _TrivialExpressionInfo<Variable, Type>(this);
     }
 
-    Type? previousType = info.promotedTypes?.last;
-    previousType ??= reference.getDeclaredType(typeOperations);
-
+    Type previousType = referenceWithType.type;
     FlowModel<Variable, Type> modelIfSuccessful = this;
     Type? typeIfSuccess = typeOperations.tryPromoteToType(type, previousType);
     if (typeIfSuccess != null &&
         !typeOperations.isSameType(typeIfSuccess, previousType)) {
       assert(typeOperations.isSubtypeOf(typeIfSuccess, previousType),
           "Expected $typeIfSuccess to be a subtype of $previousType.");
-      modelIfSuccessful =
-          _finishTypeTest(typeOperations, reference, info, type, typeIfSuccess);
+      modelIfSuccessful = _finishTypeTest(typeOperations,
+          referenceWithType.reference, info, type, typeIfSuccess);
     }
 
     Type factoredType = typeOperations.factor(previousType, type);
@@ -1992,8 +2021,8 @@
     } else {
       typeIfFailed = factoredType;
     }
-    FlowModel<Variable, Type> modelIfFailed =
-        _finishTypeTest(typeOperations, reference, info, type, typeIfFailed);
+    FlowModel<Variable, Type> modelIfFailed = _finishTypeTest(
+        typeOperations, referenceWithType.reference, info, type, typeIfFailed);
 
     return new ExpressionInfo<Variable, Type>(
         this, modelIfSuccessful, modelIfFailed);
@@ -2292,13 +2321,13 @@
 
   /// Implementation of the visitor pattern for non-promotion reasons.
   R accept<R, Node extends Object, Expression extends Object,
-          Variable extends Object>(
-      NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor);
+          Variable extends Object, Type extends Object>(
+      NonPromotionReasonVisitor<R, Node, Expression, Variable, Type> visitor);
 }
 
 /// Implementation of the visitor pattern for non-promotion reasons.
 abstract class NonPromotionReasonVisitor<R, Node extends Object,
-    Expression extends Object, Variable extends Object> {
+    Expression extends Object, Variable extends Object, Type extends Object> {
   NonPromotionReasonVisitor._() : assert(false, 'Do not extend this class');
 
   R visitDemoteViaExplicitWrite(
@@ -2307,27 +2336,33 @@
   R visitDemoteViaForEachVariableWrite(
       DemoteViaForEachVariableWrite<Variable, Node> reason);
 
-  R visitPropertyNotPromoted(PropertyNotPromoted reason);
+  R visitPropertyNotPromoted(PropertyNotPromoted<Type> reason);
 
   R visitThisNotPromoted(ThisNotPromoted reason);
 }
 
 /// Non-promotion reason describing the situation where an expression was not
 /// promoted due to the fact that it's a property get.
-class PropertyNotPromoted extends NonPromotionReason {
+class PropertyNotPromoted<Type extends Object> extends NonPromotionReason {
   /// The name of the property.
   final String propertyName;
 
-  PropertyNotPromoted(this.propertyName);
+  /// The static type of the property at the time of the access.  This is the
+  /// type that was passed to [FlowAnalysis.whyNotPromoted]; it is provided to
+  /// the client as a convenience for ID testing.
+  final Type staticType;
+
+  PropertyNotPromoted(this.propertyName, this.staticType);
 
   @override
   String get shortName => 'propertyNotPromoted';
 
   @override
   R accept<R, Node extends Object, Expression extends Object,
-              Variable extends Object>(
-          NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor) =>
-      visitor.visitPropertyNotPromoted(this);
+              Variable extends Object, Type extends Object>(
+          NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
+              visitor) =>
+      visitor.visitPropertyNotPromoted(this as PropertyNotPromoted<Type>);
 }
 
 /// Immutable data structure modeling the reachability of the given point in the
@@ -2479,10 +2514,6 @@
 /// why promotion did not occur.
 @visibleForTesting
 abstract class Reference<Variable extends Object, Type extends Object> {
-  /// Retrieves the declared type of this reference.  This is used as the
-  /// starting point for promotions.
-  Type getDeclaredType(TypeOperations<Variable, Type> typeOperations);
-
   /// Gets the info for this reference, creating it if it doesn't exist.
   VariableModel<Variable, Type> getInfo(
           Map<Variable?, VariableModel<Variable, Type>> variableInfo) =>
@@ -2492,6 +2523,7 @@
   /// is the map that will be returned from [FlowAnalysis.whyNotPromoted].
   Map<Type, NonPromotionReason> getNonPromotionReasons(
       Map<Variable?, VariableModel<Variable, Type>> variableInfo,
+      Type staticType,
       TypeOperations<Variable, Type> typeOperations);
 
   /// Creates a reference representing a get of a property called [propertyName]
@@ -2508,6 +2540,16 @@
       Map<Variable?, VariableModel<Variable, Type>> variableInfo);
 }
 
+/// Container object combining a [Reference] object with its static type.
+@visibleForTesting
+class ReferenceWithType<Variable extends Object, Type extends Object> {
+  final Reference<Variable, Type> reference;
+
+  final Type type;
+
+  ReferenceWithType(this.reference, this.type);
+}
+
 /// Data structure representing a unique value that a variable might take on
 /// during execution of the code being analyzed.  SSA nodes are immutable (so
 /// they can be safety shared among data structures) and have identity (so that
@@ -2552,8 +2594,9 @@
 
   @override
   R accept<R, Node extends Object, Expression extends Object,
-              Variable extends Object>(
-          NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor) =>
+              Variable extends Object, Type extends Object>(
+          NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
+              visitor) =>
       visitor.visitThisNotPromoted(this);
 }
 
@@ -2573,9 +2616,6 @@
 
 /// Operations on types, abstracted from concrete type interfaces.
 abstract class TypeOperations<Variable extends Object, Type extends Object> {
-  /// Gets the representation of the top type (`Object?`) in the type system.
-  Type get topType;
-
   /// Classifies the given type into one of the three categories defined by
   /// the [TypeClassification] enum.
   TypeClassification classifyType(Type type);
@@ -3214,12 +3254,9 @@
   VariableReference(this.variable);
 
   @override
-  Type getDeclaredType(TypeOperations<Variable, Type> typeOperations) =>
-      typeOperations.variableType(variable);
-
-  @override
   Map<Type, NonPromotionReason> getNonPromotionReasons(
       Map<Variable?, VariableModel<Variable, Type>> variableInfo,
+      Type staticType,
       TypeOperations<Variable, Type> typeOperations) {
     Map<Type, NonPromotionReason> result = <Type, NonPromotionReason>{};
     VariableModel<Variable, Type>? currentVariableInfo = variableInfo[variable];
@@ -3339,7 +3376,7 @@
 
   /// If the LHS of `==` or `!=` is a reference, the thing being referred to.
   /// Otherwise `null`.
-  final Reference<Variable, Type>? _leftOperandReference;
+  final ReferenceWithType<Variable, Type>? _leftOperandReference;
 
   _EqualityOpContext(ExpressionInfo<Variable, Type>? conditionInfo,
       this._leftOperandType, this._leftOperandReference)
@@ -3385,7 +3422,7 @@
 
   /// If [_expressionVariable] is not `null`, the reference corresponding to it.
   /// Otherwise `null`.
-  Reference<Variable, Type>? _expressionReference;
+  ReferenceWithType<Variable, Type>? _expressionReference;
 
   int _functionNestingLevel = 0;
 
@@ -3398,10 +3435,11 @@
 
   @override
   void asExpression_end(Expression subExpression, Type type) {
-    Reference<Variable, Type>? reference =
+    ReferenceWithType<Variable, Type>? referenceWithType =
         _getExpressionReference(subExpression);
-    if (reference == null) return;
-    _current = _current.tryPromoteForTypeCast(typeOperations, reference, type);
+    if (referenceWithType == null) return;
+    _current =
+        _current.tryPromoteForTypeCast(typeOperations, referenceWithType, type);
   }
 
   @override
@@ -3508,10 +3546,11 @@
     _EqualityOpContext<Variable, Type> context =
         _stack.removeLast() as _EqualityOpContext<Variable, Type>;
     ExpressionInfo<Variable, Type>? lhsInfo = context._conditionInfo;
-    Reference<Variable, Type>? lhsReference = context._leftOperandReference;
+    ReferenceWithType<Variable, Type>? lhsReference =
+        context._leftOperandReference;
     Type leftOperandType = context._leftOperandType;
     ExpressionInfo<Variable, Type>? rhsInfo = _getExpressionInfo(rightOperand);
-    Reference<Variable, Type>? rhsReference =
+    ReferenceWithType<Variable, Type>? rhsReference =
         _getExpressionReference(rightOperand);
     TypeClassification leftOperandTypeClassification =
         typeOperations.classifyType(leftOperandType);
@@ -3692,7 +3731,7 @@
   @override
   void ifNullExpression_rightBegin(
       Expression leftHandSide, Type leftHandSideType) {
-    Reference<Variable, Type>? lhsReference =
+    ReferenceWithType<Variable, Type>? lhsReference =
         _getExpressionReference(leftHandSide);
     FlowModel<Variable, Type> promoted;
     _current = _current.split();
@@ -3771,7 +3810,7 @@
   @override
   void isExpression_end(Expression isExpression, Expression subExpression,
       bool isNot, Type type) {
-    Reference<Variable, Type>? subExpressionReference =
+    ReferenceWithType<Variable, Type>? subExpressionReference =
         _getExpressionReference(subExpression);
     if (subExpressionReference != null) {
       ExpressionInfo<Variable, Type> expressionInfo = _current
@@ -3865,7 +3904,7 @@
 
   @override
   void nonNullAssert_end(Expression operand) {
-    Reference<Variable, Type>? operandReference =
+    ReferenceWithType<Variable, Type>? operandReference =
         _getExpressionReference(operand);
     if (operandReference != null) {
       _current =
@@ -3886,7 +3925,7 @@
     assert(targetType != null);
     _current = _current.split();
     _stack.add(new _NullAwareAccessContext<Variable, Type>(_current));
-    Reference<Variable, Type>? targetReference =
+    ReferenceWithType<Variable, Type>? targetReference =
         _getExpressionReference(target);
     if (targetReference != null) {
       _current =
@@ -3908,8 +3947,13 @@
   @override
   void promote(Variable variable, Type type) {
     _current = _current
-        .tryPromoteForTypeCheck(typeOperations,
-            new VariableReference<Variable, Type>(variable), type)
+        .tryPromoteForTypeCheck(
+            typeOperations,
+            new ReferenceWithType<Variable, Type>(
+                new VariableReference<Variable, Type>(variable),
+                promotedType(variable) ??
+                    typeOperations.variableType(variable)),
+            type)
         .ifTrue;
   }
 
@@ -3919,12 +3963,15 @@
   }
 
   @override
-  void propertyGet(
-      Expression wholeExpression, Expression target, String propertyName) {
-    Reference<Variable, Type>? reference = _getExpressionReference(target);
+  void propertyGet(Expression wholeExpression, Expression target,
+      String propertyName, Type staticType) {
+    Reference<Variable, Type>? reference =
+        _getExpressionReference(target)?.reference;
     if (reference != null) {
       _storeExpressionReference(
-          wholeExpression, reference.propertyGet(propertyName));
+          wholeExpression,
+          new ReferenceWithType<Variable, Type>(
+              reference.propertyGet(propertyName), staticType));
     }
   }
 
@@ -3973,14 +4020,21 @@
   }
 
   @override
-  void thisOrSuper(Expression expression) {
-    _storeExpressionReference(expression, new _ThisReference<Variable, Type>());
+  void thisOrSuper(Expression expression, Type staticType) {
+    _storeExpressionReference(
+        expression,
+        new ReferenceWithType<Variable, Type>(
+            new _ThisReference<Variable, Type>(), staticType));
   }
 
   @override
-  void thisOrSuperPropertyGet(Expression expression, String propertyName) {
-    _storeExpressionReference(expression,
-        new _ThisReference<Variable, Type>().propertyGet(propertyName));
+  void thisOrSuperPropertyGet(
+      Expression expression, String propertyName, Type staticType) {
+    _storeExpressionReference(
+        expression,
+        new ReferenceWithType<Variable, Type>(
+            new _ThisReference<Variable, Type>().propertyGet(propertyName),
+            staticType));
   }
 
   @override
@@ -4067,16 +4121,19 @@
   Type? variableRead(Expression expression, Variable variable) {
     VariableReference<Variable, Type> variableReference =
         new VariableReference<Variable, Type>(variable);
-    _storeExpressionReference(expression, variableReference);
     VariableModel<Variable, Type> variableModel =
         variableReference.getInfo(_current.variableInfo);
+    Type? promotedType = variableModel.promotedTypes?.last;
+    Type currentType = promotedType ?? typeOperations.variableType(variable);
+    _storeExpressionReference(expression,
+        new ReferenceWithType<Variable, Type>(variableReference, currentType));
     ExpressionInfo<Variable, Type>? expressionInfo = variableModel
         .ssaNode?.expressionInfo
         ?.rebaseForward(typeOperations, _current);
     if (expressionInfo != null) {
       _storeExpressionInfo(expression, expressionInfo);
     }
-    return variableModel.promotedTypes?.last;
+    return promotedType;
   }
 
   @override
@@ -4107,21 +4164,22 @@
   }
 
   @override
-  Map<Type, NonPromotionReason> whyNotPromoted(Expression? target) {
-    Reference<Variable, Type>? reference;
-    if (target == null) {
-      reference = new _ThisReference<Variable, Type>();
-    } else if (identical(target, _expressionWithReference)) {
-      reference = _expressionReference;
-    }
-    if (reference != null) {
-      return reference.getNonPromotionReasons(
-          _current.variableInfo, typeOperations);
+  Map<Type, NonPromotionReason> whyNotPromoted(Expression target) {
+    ReferenceWithType<Variable, Type>? referenceWithType = _expressionReference;
+    if (referenceWithType != null) {
+      return referenceWithType.reference.getNonPromotionReasons(
+          _current.variableInfo, referenceWithType.type, typeOperations);
     }
     return {};
   }
 
   @override
+  Map<Type, NonPromotionReason> whyNotPromotedImplicitThis(Type staticType) {
+    return new _ThisReference<Variable, Type>().getNonPromotionReasons(
+        _current.variableInfo, staticType, typeOperations);
+  }
+
+  @override
   void write(Expression expression, Variable variable, Type writtenType,
       Expression? writtenExpression) {
     ExpressionInfo<Variable, Type>? expressionInfo = writtenExpression == null
@@ -4174,9 +4232,11 @@
   /// Gets the [Reference] associated with the [expression] (which should be the
   /// last expression that was traversed).  If there is no [Reference]
   /// associated with the [expression], then `null` is returned.
-  Reference<Variable, Type>? _getExpressionReference(Expression? expression) {
+  ReferenceWithType<Variable, Type>? _getExpressionReference(
+      Expression? expression) {
     if (identical(expression, _expressionWithReference)) {
-      Reference<Variable, Type>? expressionReference = _expressionReference;
+      ReferenceWithType<Variable, Type>? expressionReference =
+          _expressionReference;
       _expressionReference = null;
       return expressionReference;
     } else {
@@ -4205,8 +4265,8 @@
 
   /// Associates [expression], which should be the most recently visited
   /// expression, with the given [Reference] object.
-  void _storeExpressionReference(
-      Expression expression, Reference<Variable, Type> expressionReference) {
+  void _storeExpressionReference(Expression expression,
+      ReferenceWithType<Variable, Type> expressionReference) {
     _expressionWithReference = expression;
     _expressionReference = expressionReference;
   }
@@ -4637,8 +4697,8 @@
   }
 
   @override
-  void propertyGet(
-      Expression wholeExpression, Expression target, String propertyName) {}
+  void propertyGet(Expression wholeExpression, Expression target,
+      String propertyName, Type staticType) {}
 
   @override
   SsaNode<Variable, Type>? ssaNodeForTesting(Variable variable) {
@@ -4655,10 +4715,11 @@
   void switchStatement_expressionEnd(Statement switchStatement) {}
 
   @override
-  void thisOrSuper(Expression expression) {}
+  void thisOrSuper(Expression expression, Type staticType) {}
 
   @override
-  void thisOrSuperPropertyGet(Expression expression, String propertyName) {}
+  void thisOrSuperPropertyGet(
+      Expression expression, String propertyName, Type staticType) {}
 
   @override
   void tryCatchStatement_bodyBegin() {}
@@ -4703,7 +4764,12 @@
   void whileStatement_end() {}
 
   @override
-  Map<Type, NonPromotionReason> whyNotPromoted(Expression? target) {
+  Map<Type, NonPromotionReason> whyNotPromoted(Expression target) {
+    return {};
+  }
+
+  @override
+  Map<Type, NonPromotionReason> whyNotPromotedImplicitThis(Type staticType) {
     return {};
   }
 
@@ -4856,44 +4922,15 @@
   _PropertyGetReference(this.target, this.propertyName);
 
   @override
-  Type getDeclaredType(TypeOperations<Variable, Type> typeOperations) {
-    // Since we don't actually support property promotion, we just compute what
-    // promotions would have occurred if we *did* support it (for the purpose of
-    // issuing more useful error messages), we have some leeway in how we define
-    // the "declared type" of a property.  It's tempting to define it as the
-    // return type of the referenced getter, but this is problematic for two
-    // reasons: (1) we don't have the necessary hooks to ask the client what
-    // this type is, and (2) the referenced getter can become more specific due
-    // to the presence of other promotions, breaking the invariant that promoted
-    // types are expected to be subtypes of the declared type, e.g.:
-    //
-    //   abstract class C { num? get x; }
-    //   abstract class D extends C { int? get x; }
-    //   f(C c) {
-    //     if (c.x != null) { // "promotes" c.x to `num`
-    //       if (c is D) { // promotes c to D, so c.x now refers to an `int?`
-    //         // Invariant broken: `num` is not a subtype of `int?`
-    //       }
-    //     }
-    //   }
-    //
-    // Rather than break the invariant (which could lead to unexpected behaviors
-    // of flow analysis, including possibly crashes), it seems wiser to simply
-    // define the "declared type" for properties to be the top type; in practice
-    // this still produces useful results, and it doesn't violate soundness
-    // because we don't actually promote property references.
-    return typeOperations.topType;
-  }
-
-  @override
   Map<Type, NonPromotionReason> getNonPromotionReasons(
       Map<Variable?, VariableModel<Variable, Type>> variableInfo,
+      Type staticType,
       TypeOperations<Variable, Type> typeOperations) {
     Map<Type, NonPromotionReason> result = <Type, NonPromotionReason>{};
     List<Type>? promotedTypes = _getInfo(variableInfo)?.promotedTypes;
     if (promotedTypes != null) {
       for (Type type in promotedTypes) {
-        result[type] = new PropertyNotPromoted(propertyName);
+        result[type] = new PropertyNotPromoted(propertyName, staticType);
       }
     }
     return result;
@@ -4957,15 +4994,9 @@
 class _ThisReference<Variable extends Object, Type extends Object>
     extends Reference<Variable, Type> {
   @override
-  Type getDeclaredType(TypeOperations<Variable, Type> typeOperations) {
-    // TODO(paulberry): can we return the actual type?  Would that have a
-    // user-visible effect?
-    return typeOperations.topType;
-  }
-
-  @override
   Map<Type, NonPromotionReason> getNonPromotionReasons(
       Map<Variable?, VariableModel<Variable, Type>> variableInfo,
+      Type staticType,
       TypeOperations<Variable, Type> typeOperations) {
     Map<Type, NonPromotionReason> result = <Type, NonPromotionReason>{};
     List<Type>? promotedTypes = _getInfo(variableInfo)?.promotedTypes;
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
index d1a4d13..024a4c6 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
@@ -144,9 +144,9 @@
         [List<Statement>? ifFalse]) =>
     new _If(condition, ifTrue, ifFalse);
 
-Statement implicitThis_whyNotPromoted(
+Statement implicitThis_whyNotPromoted(String staticType,
         void Function(Map<Type, NonPromotionReason>) callback) =>
-    new _WhyNotPromoted_ImplicitThis(callback);
+    new _WhyNotPromoted_ImplicitThis(Type(staticType), callback);
 
 Statement labeled(Statement body) => new _LabeledStatement(body);
 
@@ -161,7 +161,7 @@
 Expression this_(String type) => new _This(Type(type));
 
 Expression thisOrSuperPropertyGet(String name, {String type = 'Object?'}) =>
-    new _ThisOrSuperPropertyGet(name, type);
+    new _ThisOrSuperPropertyGet(name, Type(type));
 
 Expression throw_(Expression operand) => new _Throw(operand);
 
@@ -284,7 +284,7 @@
 
   /// If `this` is an expression `x`, creates the expression `x.name`.
   Expression propertyGet(String name, {String type = 'Object?'}) =>
-      new _PropertyGet(this, name, type);
+      new _PropertyGet(this, name, Type(type));
 
   /// If `this` is an expression `x`, creates a pseudo-expression that models
   /// evaluation of `x` followed by execution of [stmt].  This can be used to
@@ -435,9 +435,6 @@
 
   Harness({this.legacy = false});
 
-  @override
-  Type get topType => Type('Object?');
-
   /// Updates the harness so that when a [factor] query is invoked on types
   /// [from] and [what], [result] will be returned.
   void addFactor(String from, String what, String result) {
@@ -1477,7 +1474,7 @@
 
   final String propertyName;
 
-  final String type;
+  final Type type;
 
   _PropertyGet(this.target, this.propertyName, this.type);
 
@@ -1490,8 +1487,8 @@
   Type _visit(
       Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
     target._visit(h, flow);
-    flow.propertyGet(this, target, propertyName);
-    return Type(type);
+    flow.propertyGet(this, target, propertyName, type);
+    return type;
   }
 }
 
@@ -1566,7 +1563,7 @@
   @override
   Type _visit(
       Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.thisOrSuper(this);
+    flow.thisOrSuper(this, type);
     return type;
   }
 }
@@ -1574,7 +1571,7 @@
 class _ThisOrSuperPropertyGet extends Expression {
   final String propertyName;
 
-  final String type;
+  final Type type;
 
   _ThisOrSuperPropertyGet(this.propertyName, this.type);
 
@@ -1584,8 +1581,8 @@
   @override
   Type _visit(
       Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.thisOrSuperPropertyGet(this, propertyName);
-    return Type(type);
+    flow.thisOrSuperPropertyGet(this, propertyName, type);
+    return type;
   }
 }
 
@@ -1760,9 +1757,11 @@
 }
 
 class _WhyNotPromoted_ImplicitThis extends Statement {
+  final Type staticType;
+
   final void Function(Map<Type, NonPromotionReason>) callback;
 
-  _WhyNotPromoted_ImplicitThis(this.callback) : super._();
+  _WhyNotPromoted_ImplicitThis(this.staticType, this.callback) : super._();
 
   @override
   String toString() => 'implicit this (whyNotPromoted)';
@@ -1776,7 +1775,7 @@
     assert(!Type._allowComparisons);
     Type._allowComparisons = true;
     try {
-      callback(flow.whyNotPromoted(null));
+      callback(flow.whyNotPromotedImplicitThis(staticType));
     } finally {
       Type._allowComparisons = false;
     }
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index f594559..67012be 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -518,7 +518,9 @@
     });
 
     test('equalityOp_end does not set reachability for `this`', () {
-      var h = Harness();
+      var h = Harness()
+        ..addSubtype('Null', 'C', false)
+        ..addFactor('C', 'Null', 'C');
       h.addSubtype('C', 'Object', true);
       h.run([
         if_(this_('C').is_('Null'), [
@@ -1461,7 +1463,9 @@
     });
 
     test('isExpression_end() does not set reachability for `this`', () {
-      var h = Harness();
+      var h = Harness()
+        ..addSubtype('Never', 'C', true)
+        ..addFactor('C', 'Never', 'C');
       h.run([
         if_(this_('C').is_('Never'), [
           checkReachable(true),
@@ -3319,34 +3323,28 @@
       test('unpromoted -> unchanged (same)', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial);
-        var s2 =
-            s1.tryPromoteForTypeCheck(h, _varRef(intVar), Type('int')).ifTrue;
+        var s2 = s1._tryPromoteForTypeCheck(h, intVar, 'int').ifTrue;
         expect(s2, same(s1));
       });
 
       test('unpromoted -> unchanged (supertype)', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial);
-        var s2 = s1
-            .tryPromoteForTypeCheck(h, _varRef(intVar), Type('Object'))
-            .ifTrue;
+        var s2 = s1._tryPromoteForTypeCheck(h, intVar, 'Object').ifTrue;
         expect(s2, same(s1));
       });
 
       test('unpromoted -> unchanged (unrelated)', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial);
-        var s2 = s1
-            .tryPromoteForTypeCheck(h, _varRef(intVar), Type('String'))
-            .ifTrue;
+        var s2 = s1._tryPromoteForTypeCheck(h, intVar, 'String').ifTrue;
         expect(s2, same(s1));
       });
 
       test('unpromoted -> subtype', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial);
-        var s2 =
-            s1.tryPromoteForTypeCheck(h, _varRef(intQVar), Type('int')).ifTrue;
+        var s2 = s1._tryPromoteForTypeCheck(h, intQVar, 'int').ifTrue;
         expect(s2.reachable.overallReachable, true);
         expect(s2.variableInfo, {
           intQVar: _matchVariableModel(chain: ['int'], ofInterest: ['int'])
@@ -3356,44 +3354,36 @@
       test('promoted -> unchanged (same)', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
-        var s2 = s1
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
-            .ifTrue;
+        var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'int').ifTrue;
         expect(s2, same(s1));
       });
 
       test('promoted -> unchanged (supertype)', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
-        var s2 = s1
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('Object'))
-            .ifTrue;
+        var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'Object').ifTrue;
         expect(s2, same(s1));
       });
 
       test('promoted -> unchanged (unrelated)', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
-        var s2 = s1
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('String'))
-            .ifTrue;
+        var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'String').ifTrue;
         expect(s2, same(s1));
       });
 
       test('promoted -> subtype', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int?'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
             .ifTrue;
-        var s2 = s1
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
-            .ifTrue;
+        var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'int').ifTrue;
         expect(s2.reachable.overallReachable, true);
         expect(s2.variableInfo, {
           objectQVar: _matchVariableModel(
@@ -3450,7 +3440,7 @@
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
             .declare(objectQVar, true)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
         expect(s1.variableInfo, contains(objectQVar));
         var s2 = s1.write(_MockNonPromotionReason(), objectQVar, Type('int?'),
@@ -3469,9 +3459,9 @@
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
             .declare(objectQVar, true)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifTrue
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
         expect(s1.variableInfo, {
           objectQVar: _matchVariableModel(
@@ -3496,11 +3486,11 @@
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
             .declare(objectQVar, true)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifTrue
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'num')
             .ifTrue
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
         expect(s1.variableInfo, {
           objectQVar: _matchVariableModel(
@@ -3525,9 +3515,9 @@
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
             .declare(objectQVar, true)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifTrue
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'num')
             .ifTrue;
         expect(s1.variableInfo, {
           objectQVar: _matchVariableModel(
@@ -3553,9 +3543,9 @@
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
             .declare(objectQVar, true)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifTrue
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'num')
             .ifTrue;
         expect(s1.variableInfo, {
           objectQVar: _matchVariableModel(
@@ -3620,7 +3610,7 @@
           var h = Harness();
           var s1 = FlowModel<Var, Type>(Reachability.initial)
               .declare(objectQVar, true)
-              .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int?'))
+              ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
               .ifTrue;
           expect(s1.variableInfo, {
             objectQVar: _matchVariableModel(
@@ -3642,7 +3632,7 @@
           var h = Harness();
           var s1 = FlowModel<Var, Type>(Reachability.initial)
               .declare(objectQVar, true)
-              .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int?'))
+              ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
               .ifFalse;
           expect(s1.variableInfo, {
             objectQVar: _matchVariableModel(
@@ -3665,7 +3655,7 @@
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
             .declare(objectQVar, true)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifFalse;
         expect(s1.variableInfo, {
           objectQVar: _matchVariableModel(
@@ -3687,9 +3677,9 @@
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
             .declare(objectQVar, true)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
             .ifTrue
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int?'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
             .ifFalse;
         expect(s1.variableInfo, {
           objectQVar: _matchVariableModel(
@@ -3756,9 +3746,9 @@
 
             var s1 = FlowModel<Var, Type>(Reachability.initial)
                 .declare(x, true)
-                .tryPromoteForTypeCheck(h, _varRef(x), Type('B?'))
+                ._tryPromoteForTypeCheck(h, x, 'B?')
                 .ifFalse
-                .tryPromoteForTypeCheck(h, _varRef(x), Type('A?'))
+                ._tryPromoteForTypeCheck(h, x, 'A?')
                 .ifFalse;
             expect(s1.variableInfo, {
               x: _matchVariableModel(
@@ -3782,9 +3772,9 @@
 
             var s1 = FlowModel<Var, Type>(Reachability.initial)
                 .declare(x, true)
-                .tryPromoteForTypeCheck(h, _varRef(x), Type('A?'))
+                ._tryPromoteForTypeCheck(h, x, 'A?')
                 .ifFalse
-                .tryPromoteForTypeCheck(h, _varRef(x), Type('B?'))
+                ._tryPromoteForTypeCheck(h, x, 'B?')
                 .ifFalse;
             expect(s1.variableInfo, {
               x: _matchVariableModel(
@@ -3808,9 +3798,9 @@
 
             var s1 = FlowModel<Var, Type>(Reachability.initial)
                 .declare(x, true)
-                .tryPromoteForTypeCheck(h, _varRef(x), Type('A'))
+                ._tryPromoteForTypeCheck(h, x, 'A')
                 .ifFalse
-                .tryPromoteForTypeCheck(h, _varRef(x), Type('A?'))
+                ._tryPromoteForTypeCheck(h, x, 'A?')
                 .ifFalse;
             expect(s1.variableInfo, {
               x: _matchVariableModel(
@@ -3835,9 +3825,9 @@
             var h = Harness();
             var s1 = FlowModel<Var, Type>(Reachability.initial)
                 .declare(objectQVar, true)
-                .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+                ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
                 .ifFalse
-                .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num*'))
+                ._tryPromoteForTypeCheck(h, objectQVar, 'num*')
                 .ifFalse;
             expect(s1.variableInfo, {
               objectQVar: _matchVariableModel(
@@ -3863,9 +3853,9 @@
           var h = Harness();
           var s1 = FlowModel<Var, Type>(Reachability.initial)
               .declare(objectQVar, true)
-              .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+              ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
               .ifFalse
-              .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num*'))
+              ._tryPromoteForTypeCheck(h, objectQVar, 'num*')
               .ifFalse;
           expect(s1.variableInfo, {
             objectQVar: _matchVariableModel(
@@ -3895,9 +3885,9 @@
 
         var s1 = FlowModel<Var, Type>(Reachability.initial)
             .declare(x, true)
-            .tryPromoteForTypeCheck(h, _varRef(x), Type('num?'))
+            ._tryPromoteForTypeCheck(h, x, 'num?')
             .ifTrue
-            .tryPromoteForTypeCheck(h, _varRef(x), Type('int?'))
+            ._tryPromoteForTypeCheck(h, x, 'int?')
             .ifTrue;
         expect(s1.variableInfo, {
           x: _matchVariableModel(
@@ -3941,14 +3931,14 @@
       test('unpromoted -> unchanged', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial);
-        var s2 = s1.tryMarkNonNullable(h, _varRef(intVar)).ifTrue;
+        var s2 = s1._tryMarkNonNullable(h, intVar).ifTrue;
         expect(s2, same(s1));
       });
 
       test('unpromoted -> promoted', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial);
-        var s2 = s1.tryMarkNonNullable(h, _varRef(intQVar)).ifTrue;
+        var s2 = s1._tryMarkNonNullable(h, intQVar).ifTrue;
         expect(s2.reachable.overallReachable, true);
         expect(s2.infoFor(intQVar),
             _matchVariableModel(chain: ['int'], ofInterest: []));
@@ -3957,18 +3947,18 @@
       test('promoted -> unchanged', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
-        var s2 = s1.tryMarkNonNullable(h, _varRef(objectQVar)).ifTrue;
+        var s2 = s1._tryMarkNonNullable(h, objectQVar).ifTrue;
         expect(s2, same(s1));
       });
 
       test('promoted -> re-promoted', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int?'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
             .ifTrue;
-        var s2 = s1.tryMarkNonNullable(h, _varRef(objectQVar)).ifTrue;
+        var s2 = s1._tryMarkNonNullable(h, objectQVar).ifTrue;
         expect(s2.reachable.overallReachable, true);
         expect(s2.variableInfo, {
           objectQVar:
@@ -3979,7 +3969,7 @@
       test('promote to Never', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial);
-        var s2 = s1.tryMarkNonNullable(h, _varRef(nullVar)).ifTrue;
+        var s2 = s1._tryMarkNonNullable(h, nullVar).ifTrue;
         expect(s2.reachable.overallReachable, false);
         expect(s2.infoFor(nullVar),
             _matchVariableModel(chain: ['Never'], ofInterest: []));
@@ -3991,7 +3981,7 @@
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
             .declare(intQVar, true)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue;
         var s2 = s1.conservativeJoin([intQVar], []);
         expect(s2, isNot(same(s1)));
@@ -4005,9 +3995,9 @@
       test('written', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue
-            .tryPromoteForTypeCheck(h, _varRef(intQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, intQVar, 'int')
             .ifTrue;
         var s2 = s1.conservativeJoin([intQVar], []);
         expect(s2.reachable.overallReachable, true);
@@ -4020,9 +4010,9 @@
       test('write captured', () {
         var h = Harness();
         var s1 = FlowModel<Var, Type>(Reachability.initial)
-            .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, objectQVar, 'int')
             .ifTrue
-            .tryPromoteForTypeCheck(h, _varRef(intQVar), Type('int'))
+            ._tryPromoteForTypeCheck(h, intQVar, 'int')
             .ifTrue;
         var s2 = s1.conservativeJoin([], [intQVar]);
         expect(s2.reachable.overallReachable, true);
@@ -4112,7 +4102,7 @@
         var s0 = FlowModel<Var, Type>(Reachability.initial).declare(a, false);
         // In s1, a is write captured.  In s2 it's promoted.
         var s1 = s0.conservativeJoin([a], [a]);
-        var s2 = s0.tryPromoteForTypeCheck(h, _varRef(a), Type('int')).ifTrue;
+        var s2 = s0._tryPromoteForTypeCheck(h, a, 'int').ifTrue;
         expect(
           s1.rebaseForward(h, s2).infoFor(a),
           _matchVariableModel(writeCaptured: true, chain: isNull),
@@ -4135,14 +4125,11 @@
                 null, x, Type('Object?'), new SsaNode<Var, Type>(null), h);
           }
           if (thisType != null) {
-            s1 =
-                s1.tryPromoteForTypeCheck(h, _varRef(x), Type(thisType)).ifTrue;
+            s1 = s1._tryPromoteForTypeCheck(h, x, thisType).ifTrue;
           }
           var s2 = otherType == null
               ? s0
-              : s0
-                  .tryPromoteForTypeCheck(h, _varRef(x), Type(otherType))
-                  .ifTrue;
+              : s0._tryPromoteForTypeCheck(h, x, otherType).ifTrue;
           var result = s2.rebaseForward(h, s1);
           if (expectedChain == null) {
             expect(result.variableInfo, contains(x));
@@ -4191,23 +4178,18 @@
           var initialModel =
               FlowModel<Var, Type>(Reachability.initial).declare(x, true);
           for (var t in before) {
-            initialModel = initialModel
-                .tryPromoteForTypeCheck(h, _varRef(x), Type(t))
-                .ifTrue;
+            initialModel = initialModel._tryPromoteForTypeCheck(h, x, t).ifTrue;
           }
           _checkChain(initialModel.infoFor(x).promotedTypes, before);
           var tryModel = initialModel;
           for (var t in inTry) {
-            tryModel =
-                tryModel.tryPromoteForTypeCheck(h, _varRef(x), Type(t)).ifTrue;
+            tryModel = tryModel._tryPromoteForTypeCheck(h, x, t).ifTrue;
           }
           var expectedTryChain = before.toList()..addAll(inTry);
           _checkChain(tryModel.infoFor(x).promotedTypes, expectedTryChain);
           var finallyModel = initialModel;
           for (var t in inFinally) {
-            finallyModel = finallyModel
-                .tryPromoteForTypeCheck(h, _varRef(x), Type(t))
-                .ifTrue;
+            finallyModel = finallyModel._tryPromoteForTypeCheck(h, x, t).ifTrue;
           }
           var expectedFinallyChain = before.toList()..addAll(inFinally);
           _checkChain(
@@ -4246,9 +4228,8 @@
         var h = Harness();
         var a = Var('a', 'Object');
         var s0 = FlowModel<Var, Type>(Reachability.initial).declare(a, false);
-        var s1 = s0.tryPromoteForTypeCheck(h, _varRef(a), Type('int')).ifFalse;
-        var s2 =
-            s0.tryPromoteForTypeCheck(h, _varRef(a), Type('String')).ifFalse;
+        var s1 = s0._tryPromoteForTypeCheck(h, a, 'int').ifFalse;
+        var s2 = s0._tryPromoteForTypeCheck(h, a, 'String').ifFalse;
         expect(
           s1.rebaseForward(h, s2).infoFor(a),
           _matchVariableModel(ofInterest: ['int', 'String']),
@@ -5687,8 +5668,8 @@
     group('because this', () {
       test('explicit', () {
         var h = Harness()
-          ..addSubtype('D', 'Object?', true)
-          ..addFactor('Object?', 'D', 'Object?');
+          ..addSubtype('D', 'C', true)
+          ..addFactor('C', 'D', 'C');
         h.run([
           if_(this_('C').isNot('D'), [
             return_(),
@@ -5703,13 +5684,13 @@
 
       test('implicit', () {
         var h = Harness()
-          ..addSubtype('D', 'Object?', true)
-          ..addFactor('Object?', 'D', 'Object?');
+          ..addSubtype('D', 'C', true)
+          ..addFactor('C', 'D', 'C');
         h.run([
           if_(this_('C').isNot('D'), [
             return_(),
           ]),
-          implicitThis_whyNotPromoted((reasons) {
+          implicitThis_whyNotPromoted('C', (reasons) {
             expect(reasons.keys, unorderedEquals([Type('D')]));
             var nonPromotionReason = reasons.values.single;
             expect(nonPromotionReason, TypeMatcher<ThisNotPromoted>());
@@ -5787,14 +5768,28 @@
       'writeCaptured: ${_describeMatcher(writeCapturedMatcher)})');
 }
 
-Reference<Var, Type> _varRef(Var variable) =>
-    new VariableReference<Var, Type>(variable);
-
 class _MockNonPromotionReason extends NonPromotionReason {
   String get shortName => fail('Unexpected call to shortName');
 
   R accept<R, Node extends Object, Expression extends Object,
-              Variable extends Object>(
-          NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor) =>
+              Variable extends Object, Type extends Object>(
+          NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
+              visitor) =>
       fail('Unexpected call to accept');
 }
+
+extension on FlowModel<Var, Type> {
+  Reference<Var, Type> _varRef(Var variable) =>
+      new VariableReference<Var, Type>(variable);
+
+  ReferenceWithType<Var, Type> _varRefWithType(Var variable) =>
+      new ReferenceWithType<Var, Type>(_varRef(variable),
+          variableInfo[variable]?.promotedTypes?.last ?? variable.type);
+
+  ExpressionInfo<Var, Type> _tryPromoteForTypeCheck(
+          Harness h, Var variable, String type) =>
+      tryPromoteForTypeCheck(h, _varRefWithType(variable), Type(type));
+
+  ExpressionInfo<Var, Type> _tryMarkNonNullable(Harness h, Var variable) =>
+      tryMarkNonNullable(h, _varRefWithType(variable));
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/extension_property.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/extension_property.dart
index dbbefe9..1ac0a15 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/extension_property.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/extension_property.dart
@@ -5,17 +5,21 @@
 class C {
   get_property_via_explicit_this() {
     if (this.i == null) return;
-    this.i. /*notPromoted(propertyNotPromoted(member:E|get#i))*/ isEven;
+    this
+        .i
+        . /*notPromoted(propertyNotPromoted(target: member:E|get#i, type: int?))*/ isEven;
   }
 
   get_property_via_explicit_this_parenthesized() {
     if ((this).i == null) return;
-    (this).i. /*notPromoted(propertyNotPromoted(member:E|get#i))*/ isEven;
+    (this)
+        .i
+        . /*notPromoted(propertyNotPromoted(target: member:E|get#i, type: int?))*/ isEven;
   }
 
   get_property_by_implicit_this() {
     if (i == null) return;
-    i. /*notPromoted(propertyNotPromoted(member:E|get#i))*/ isEven;
+    i. /*notPromoted(propertyNotPromoted(target: member:E|get#i, type: int?))*/ isEven;
   }
 }
 
@@ -27,13 +31,13 @@
 class D extends C {
   get_property_by_implicit_super() {
     if (i == null) return;
-    i. /*notPromoted(propertyNotPromoted(member:E|get#i))*/ isEven;
+    i. /*notPromoted(propertyNotPromoted(target: member:E|get#i, type: int?))*/ isEven;
   }
 }
 
 get_property_via_prefixed_identifier(C c) {
   if (c.i == null) return;
-  c.i. /*notPromoted(propertyNotPromoted(member:E|get#i))*/ isEven;
+  c.i. /*notPromoted(propertyNotPromoted(target: member:E|get#i, type: int?))*/ isEven;
 }
 
 get_property_via_prefixed_identifier_mismatched_target(C c1, C c2) {
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/field.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/field.dart
index 1829ad0..bc0a5e7 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/field.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/field.dart
@@ -8,35 +8,41 @@
 
   get_field_via_explicit_this() {
     if (this.i == null) return;
-    this.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+    this
+        .i
+        . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
   }
 
   get_field_via_explicit_this_parenthesized() {
     if ((this).i == null) return;
-    (this).i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+    (this)
+        .i
+        . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
   }
 
   get_field_by_implicit_this() {
     if (i == null) return;
-    i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+    i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
   }
 }
 
 class D extends C {
   get_field_via_explicit_super() {
     if (super.i == null) return;
-    super.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+    super
+        .i
+        . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
   }
 
   get_field_by_implicit_super() {
     if (i == null) return;
-    i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+    i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
   }
 }
 
 get_field_via_prefixed_identifier(C c) {
   if (c.i == null) return;
-  c.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+  c.i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
 }
 
 get_field_via_prefixed_identifier_mismatched_target(C c1, C c2) {
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart
index 4c0d40f..d43d616 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart
@@ -17,5 +17,6 @@
 test(C1 c) {
   if (c.bad == null) return;
   for (var x
-      in /*analyzer.notPromoted(propertyNotPromoted(member:C1.bad))*/ c.bad) {}
+      in /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
+          .bad) {}
 }
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart
index b8e021a..a249136 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart
@@ -16,5 +16,6 @@
 
 test(C1 c) sync* {
   if (c.bad == null) return;
-  yield* /*analyzer.notPromoted(propertyNotPromoted(member:C1.bad))*/ c.bad;
+  yield* /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
+      .bad;
 }
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart
index 3e33316..985feaa 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart
@@ -16,8 +16,9 @@
 
 instance_method_invocation(C1 c) {
   if (c.bad == null) return;
-  /*analyzer.notPromoted(propertyNotPromoted(member:C1.bad))*/ c.bad
-      /*cfe.invoke: notPromoted(propertyNotPromoted(member:C1.bad))*/
+  /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: C2?))*/ c
+      .bad
+      /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C1.bad, type: C2?))*/
       ();
 }
 
@@ -42,8 +43,9 @@
   if (c.ok == null) return;
   c.ok();
   if (c.bad == null) return;
-  /*analyzer.notPromoted(propertyNotPromoted(member:C3.bad))*/ c.bad
-      /*cfe.invoke: notPromoted(propertyNotPromoted(member:C3.bad))*/
+  /*analyzer.notPromoted(propertyNotPromoted(target: member:C3.bad, type: C5?))*/ c
+      .bad
+      /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C3.bad, type: C5?))*/
       ();
 }
 
@@ -57,8 +59,9 @@
 
 instance_getter_invocation(C6 c) {
   if (c.bad == null) return;
-  /*analyzer.notPromoted(propertyNotPromoted(member:C6.bad))*/ c.bad
-      /*cfe.invoke: notPromoted(propertyNotPromoted(member:C6.bad))*/
+  /*analyzer.notPromoted(propertyNotPromoted(target: member:C6.bad, type: C7?))*/ c
+      .bad
+      /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C6.bad, type: C7?))*/
       ();
 }
 
@@ -83,8 +86,9 @@
   if (c.ok == null) return;
   c.ok();
   if (c.bad == null) return;
-  /*analyzer.notPromoted(propertyNotPromoted(member:C8.bad))*/ c.bad
-      /*cfe.invoke: notPromoted(propertyNotPromoted(member:C8.bad))*/
+  /*analyzer.notPromoted(propertyNotPromoted(target: member:C8.bad, type: C10?))*/ c
+      .bad
+      /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C8.bad, type: C10?))*/
       ();
 }
 
@@ -94,8 +98,9 @@
 
 function_invocation(C11 c) {
   if (c.bad == null) return;
-  /*analyzer.notPromoted(propertyNotPromoted(member:C11.bad))*/ c.bad
-      /*cfe.invoke: notPromoted(propertyNotPromoted(member:C11.bad))*/
+  /*analyzer.notPromoted(propertyNotPromoted(target: member:C11.bad, type: void Function()?))*/ c
+      .bad
+      /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C11.bad, type: void Function()?))*/
       ();
 }
 
@@ -112,8 +117,8 @@
   if (c.bad == null) return;
   c.bad
       .
-      /*analyzer.notPromoted(propertyNotPromoted(member:C12.bad))*/
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C12.bad, type: C13?))*/
       foo
-      /*cfe.invoke: notPromoted(propertyNotPromoted(member:C12.bad))*/
+      /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C12.bad, type: C13?))*/
       ();
 }
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart
index 40cc053..8fc9608 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart
@@ -39,7 +39,7 @@
 
 property_get_of_expression(C c) {
   if (c.i == null) return;
-  c.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+  c.i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
 }
 
 extension_property_get_of_expression(C c) {
@@ -48,8 +48,8 @@
   c
       .i
       .
-      /*cfe.invoke: notPromoted(propertyNotPromoted(member:C.i))*/
-      /*analyzer.notPromoted(propertyNotPromoted(member:C.i))*/
+      /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
       propertyOnNonNullInt;
 }
 
@@ -57,8 +57,8 @@
   if (c.i == null) return;
   c.i
       .
-      /*cfe.invoke: notPromoted(propertyNotPromoted(member:C.i))*/
-      /*analyzer.notPromoted(propertyNotPromoted(member:C.i))*/
+      /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
       abs();
 }
 
@@ -67,8 +67,8 @@
   c.i.methodOnNullableInt();
   c.i
       .
-      /*cfe.invoke: notPromoted(propertyNotPromoted(member:C.i))*/
-      /*analyzer.notPromoted(propertyNotPromoted(member:C.i))*/
+      /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
       methodOnNonNullInt();
 }
 
@@ -76,7 +76,7 @@
   if (c.f == null) return;
   c.f
       .
-      /*cfe.invoke: notPromoted(propertyNotPromoted(member:C.f))*/
-      /*analyzer.notPromoted(propertyNotPromoted(member:C.f))*/
+      /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C.f, type: void Function()?))*/
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C.f, type: void Function()?))*/
       call();
 }
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart
index d3f6451..8398f56 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart
@@ -16,6 +16,7 @@
 test(C1 c) {
   if (c.bad == null) return;
   return [
-    ... /*analyzer.notPromoted(propertyNotPromoted(member:C1.bad))*/ c.bad
+    ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
+        .bad
   ];
 }
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/property.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/property.dart
index 24b85cc..90fe382 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/property.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/property.dart
@@ -8,35 +8,41 @@
 
   get_property_via_explicit_this() {
     if (this.i == null) return;
-    this.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+    this
+        .i
+        . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
   }
 
   get_property_via_explicit_this_parenthesized() {
     if ((this).i == null) return;
-    (this).i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+    (this)
+        .i
+        . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
   }
 
   get_property_by_implicit_this() {
     if (i == null) return;
-    i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+    i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
   }
 }
 
 class D extends C {
   get_property_via_explicit_super() {
     if (super.i == null) return;
-    super.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+    super
+        .i
+        . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
   }
 
   get_property_by_implicit_super() {
     if (i == null) return;
-    i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+    i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
   }
 }
 
 get_property_via_prefixed_identifier(C c) {
   if (c.i == null) return;
-  c.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+  c.i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
 }
 
 get_property_via_prefixed_identifier_mismatched_target(C c1, C c2) {
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index abacc10..6fd6cb7 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -362,17 +362,19 @@
 
   void _checkForAndroidManifestXmlUpdate(String path) {
     if (file_paths.isAndroidManifestXml(pathContext, path)) {
-      var context = getContextFor(path);
-      var driver = context.driver;
-      _analyzeAndroidManifestXml(driver, path);
+      var driver = getDriverFor(path);
+      if (driver != null) {
+        _analyzeAndroidManifestXml(driver, path);
+      }
     }
   }
 
   void _checkForFixDataYamlUpdate(String path) {
     if (file_paths.isFixDataYaml(pathContext, path)) {
-      var context = getContextFor(path);
-      var driver = context.driver;
-      _analyzeFixDataYaml(driver, path);
+      var driver = getDriverFor(path);
+      if (driver != null) {
+        _analyzeFixDataYaml(driver, path);
+      }
     }
   }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index 7f4ab1f..5280479 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -237,7 +237,7 @@
   ) sync* {
     final errorCode = diagnostic.errorCode;
     if (errorCode is LintCode) {
-      var fixes = FixProcessor.lintProducerMap2[errorCode.name];
+      var fixes = FixProcessor.lintProducerMap2[errorCode.name] ?? [];
       for (var fix in fixes) {
         if (fix.canBeBulkApplied) {
           final generators = fix.generators;
@@ -366,7 +366,7 @@
     try {
       var codeName = errorCode.name;
       if (errorCode is LintCode) {
-        var fixes = FixProcessor.lintProducerMap2[errorCode.name];
+        var fixes = FixProcessor.lintProducerMap2[errorCode.name] ?? [];
         for (var fix in fixes) {
           if (fix.canBeBulkApplied) {
             final generators = fix.generators;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart
index 69ba3a9..ef38ab3 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart
@@ -12,6 +12,9 @@
   FixKind get fixKind => DartFixKind.ADD_NE_NULL;
 
   @override
+  FixKind get multiFixKind => DartFixKind.ADD_NE_NULL_MULTI;
+
+  @override
   Future<void> compute(ChangeBuilder builder) async {
     var problemMessage = diagnostic.problemMessage;
     await builder.addDartFileEdit(file, (builder) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
index 1eaee2a..bc898f7 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
@@ -68,7 +68,11 @@
         toType = enclosingExecutable.declaredElement.returnType;
       }
     } else if ((parent is PrefixedIdentifier && target == parent.prefix) ||
+        parent is PostfixExpression ||
+        parent is PrefixExpression ||
+        parent is BinaryExpression ||
         (parent is PropertyAccess && target == parent.target) ||
+        (parent is CascadeExpression && target == parent.target) ||
         (parent is MethodInvocation && target == parent.target) ||
         (parent is FunctionExpressionInvocation && target == parent.function)) {
       // No need to set the `toType` because there isn't any need for a type
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart
index c101539..9b3906c 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart
@@ -89,19 +89,16 @@
     if (!_allParametersHaveTypes(node.parameters)) {
       return;
     }
-    String returnType;
-    if (node.returnType != null) {
-      returnType = utils.getNodeText(node.returnType);
-    }
+    var required = node.requiredKeyword != null ? 'required ' : '';
+    var covariant = node.covariantKeyword != null ? 'covariant ' : '';
+    var returnType =
+        node.returnType != null ? '${utils.getNodeText(node.returnType)} ' : '';
     var functionName = utils.getRangeText(range.startEnd(
         node.identifier, node.typeParameters ?? node.identifier));
     var parameters = utils.getNodeText(node.parameters);
-    String replacement;
-    if (returnType == null) {
-      replacement = 'Function$parameters $functionName';
-    } else {
-      replacement = '$returnType Function$parameters $functionName';
-    }
+    var question = node.question != null ? '?' : '';
+    var replacement =
+        '$required$covariant${returnType}Function$parameters$question $functionName';
     // add change
     await builder.addDartFileEdit(file, (builder) {
       builder.addSimpleReplacement(range.node(node), replacement);
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index c6ddc15..6e59e10 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -314,6 +314,15 @@
 class FixProcessor extends BaseProcessor {
   /// todo (pq): to replace nonLintProducerMap.
   static const Map<ErrorCode, List<FixInfo>> nonLintProducerMap2 = {
+    CompileTimeErrorCode.NON_BOOL_CONDITION: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: false,
+        generators: [
+          AddNeNull.newInstance,
+        ],
+      ),
+    ],
     HintCode.UNUSED_IMPORT: [
       FixInfo(
         canBeAppliedToFile: true,
@@ -956,10 +965,8 @@
     ],
     LintNames.unnecessary_parenthesis: [
       FixInfo(
-        // todo (pq): enable when tested
-        canBeAppliedToFile: false,
-        // not currently supported; TODO(pq): consider adding
-        canBeBulkApplied: false,
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
         generators: [
           RemoveUnnecessaryParentheses.newInstance,
         ],
diff --git a/pkg/analysis_server/test/src/cider/fixes_test.dart b/pkg/analysis_server/test/src/cider/fixes_test.dart
index 6eeaf47..8b8d691 100644
--- a/pkg/analysis_server/test/src/cider/fixes_test.dart
+++ b/pkg/analysis_server/test/src/cider/fixes_test.dart
@@ -48,7 +48,7 @@
 ''');
 
     // The file was resolved only once, even though we have 2 errors.
-    expect(fileResolver.testView.resolvedFiles, [testPath]);
+    expect(fileResolver.testView.resolvedFiles, [convertPath(testPath)]);
   }
 
   Future<void> test_createMethod() async {
diff --git a/pkg/analysis_server/test/src/plugin/plugin_manager_test.dart b/pkg/analysis_server/test/src/plugin/plugin_manager_test.dart
index 87241b1..d9bea42 100644
--- a/pkg/analysis_server/test/src/plugin/plugin_manager_test.dart
+++ b/pkg/analysis_server/test/src/plugin/plugin_manager_test.dart
@@ -32,17 +32,8 @@
   });
 }
 
-ContextRootImpl _newContextRoot(String root) {
-  var resourceProvider = PhysicalResourceProvider.INSTANCE;
-  return ContextRootImpl(
-    resourceProvider,
-    resourceProvider.getFolder(root),
-    BasicWorkspace.find(resourceProvider, {}, root),
-  );
-}
-
 @reflectiveTest
-class BuiltInPluginInfoTest {
+class BuiltInPluginInfoTest with ResourceProviderMixin, _ContextRoot {
   TestNotificationManager notificationManager;
   BuiltInPluginInfo plugin;
 
@@ -111,7 +102,7 @@
 }
 
 @reflectiveTest
-class DiscoveredPluginInfoTest {
+class DiscoveredPluginInfoTest with ResourceProviderMixin, _ContextRoot {
   TestNotificationManager notificationManager;
   String pluginPath = '/pluginDir';
   String executionPath = '/pluginDir/bin/plugin.dart';
@@ -125,10 +116,9 @@
   }
 
   void test_addContextRoot() {
-    var optionsFilePath = '/pkg1/analysis_options.yaml';
     var contextRoot1 = _newContextRoot('/pkg1');
-    contextRoot1.optionsFile =
-        contextRoot1.resourceProvider.getFile(optionsFilePath);
+    var optionsFile = getFile('/pkg1/analysis_options.yaml');
+    contextRoot1.optionsFile = optionsFile;
     var session = PluginSession(plugin);
     var channel = TestServerCommunicationChannel(session);
     plugin.currentSession = session;
@@ -139,7 +129,7 @@
     var sentRequests = channel.sentRequests;
     expect(sentRequests, hasLength(1));
     List<Map> roots = sentRequests[0].params['roots'];
-    expect(roots[0]['optionsFile'], optionsFilePath);
+    expect(roots[0]['optionsFile'], optionsFile.path);
   }
 
   void test_creation() {
@@ -447,10 +437,14 @@
         });
     pkg1Dir.deleteSync(recursive: true);
   }
+
+  ContextRootImpl _newContextRoot(String root) {
+    throw UnimplementedError();
+  }
 }
 
 @reflectiveTest
-class PluginManagerTest with ResourceProviderMixin {
+class PluginManagerTest with ResourceProviderMixin, _ContextRoot {
   String byteStorePath;
   String sdkPath;
   TestNotificationManager notificationManager;
@@ -944,3 +938,14 @@
     }
   }
 }
+
+mixin _ContextRoot on ResourceProviderMixin {
+  ContextRootImpl _newContextRoot(String root) {
+    root = convertPath(root);
+    return ContextRootImpl(
+      resourceProvider,
+      resourceProvider.getFolder(root),
+      BasicWorkspace.find(resourceProvider, {}, root),
+    );
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart
index c7b5820..fe07091 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart
@@ -11,36 +11,21 @@
 
 void main() {
   defineReflectiveSuite(() {
+    defineReflectiveTests(AddNeNullMultiTest);
     defineReflectiveTests(AddNeNullTest);
   });
 }
 
 @reflectiveTest
-class AddNeNullTest extends FixProcessorTest {
+class AddNeNullMultiTest extends FixProcessorTest {
   @override
-  FixKind get kind => DartFixKind.ADD_NE_NULL;
+  FixKind get kind => DartFixKind.ADD_NE_NULL_MULTI;
 
-  Future<void> test_nonBoolCondition() async {
-    await resolveTestCode('''
-main(String p) {
-  if (p) {
-    print(p);
-  }
-}
-''');
-    await assertHasFix('''
-main(String p) {
-  if (p != null) {
-    print(p);
-  }
-}
-''');
-  }
-
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
+  // todo (pq): add null-safe aware tests
+  // see: https://dart-review.googlesource.com/c/sdk/+/188681
   Future<void> test_nonBoolCondition_all() async {
     await resolveTestCode('''
-main(String p, String q) {
+f(String p, String q) {
   if (p) {
     print(p);
   }
@@ -50,7 +35,7 @@
 }
 ''');
     await assertHasFixAllFix(CompileTimeErrorCode.NON_BOOL_CONDITION, '''
-main(String p, String q) {
+f(String p, String q) {
   if (p != null) {
     print(p);
   }
@@ -61,3 +46,26 @@
 ''');
   }
 }
+
+@reflectiveTest
+class AddNeNullTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.ADD_NE_NULL;
+
+  Future<void> test_nonBoolCondition() async {
+    await resolveTestCode('''
+f(String p) {
+  if (p) {
+    print(p);
+  }
+}
+''');
+    await assertHasFix('''
+f(String p) {
+  if (p != null) {
+    print(p);
+  }
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
index 09750df..84fb89a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
@@ -99,6 +99,24 @@
 ''');
   }
 
+  Future<void> test_binaryOperator_leftSide() async {
+    await resolveTestCode('''
+f(int? i) => i + 1;
+''');
+    await assertHasFix('''
+f(int? i) => i! + 1;
+''');
+  }
+
+  Future<void> test_binaryOperator_rightSide() async {
+    await resolveTestCode('''
+f(int? i) => 1 + i;
+''');
+    await assertHasFix('''
+f(int? i) => 1 + i!;
+''');
+  }
+
   Future<void> test_forEachWithDeclarationCondition() async {
     await resolveTestCode('''
 void f (List<String>? args) {
@@ -225,6 +243,15 @@
 ''');
   }
 
+  Future<void> test_postfixOperator() async {
+    await resolveTestCode('''
+f(int? i) => i++;
+''');
+    await assertHasFix('''
+f(int? i) => i!++;
+''');
+  }
+
   Future<void> test_prefixedIdentifier() async {
     await resolveTestCode('''
 int f(String? s) => s.length;
@@ -234,6 +261,15 @@
 ''');
   }
 
+  Future<void> test_prefixOperator() async {
+    await resolveTestCode('''
+f(int? i) => -i;
+''');
+    await assertHasFix('''
+f(int? i) => -i!;
+''');
+  }
+
   Future<void> test_propertyAccess() async {
     await resolveTestCode('''
 int f(String? s) => (s).length;
@@ -243,6 +279,24 @@
 ''');
   }
 
+  Future<void> test_propertyAccess_cascade() async {
+    await resolveTestCode('''
+String? f(String? s) => s..length;
+''');
+    await assertHasFix('''
+String? f(String? s) => s!..length;
+''');
+  }
+
+  Future<void> test_propertyAccess_cascadeAfterNullProperty() async {
+    await resolveTestCode('''
+String? f(String? s) => s..hashCode..length;
+''');
+    await assertHasFix('''
+String? f(String? s) => s!..hashCode..length;
+''');
+  }
+
   Future<void> test_spreadList() async {
     await resolveTestCode('''
 void f (List<String>? args) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart
index 8ac6ee0..2e36f14 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart
@@ -11,6 +11,7 @@
 void main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ChangeMapTest);
+    defineReflectiveTests(NoFixTest);
   });
 }
 
@@ -36,3 +37,25 @@
     expect(errors[LintNames.unnecessary_new], 2);
   }
 }
+
+@reflectiveTest
+class NoFixTest extends BulkFixProcessorTest {
+  /// See: https://github.com/dart-lang/sdk/issues/45177
+  Future<void> test_noFix() async {
+    createAnalysisOptionsFile(experiments: experiments, lints: [
+      'avoid_catching_errors', // NOTE: not in lintProducerMap
+    ]);
+
+    await resolveTestCode('''
+void bad() {
+  try {
+  } on Error catch (e) {
+    print(e);
+  }
+}
+''');
+
+    var processor = await computeFixes();
+    expect(processor.fixDetails, isEmpty);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
index de45575..6d1ed6b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
@@ -69,7 +69,8 @@
 }
 
 @reflectiveTest
-class UseFunctionTypeSyntaxForParametersTest extends FixProcessorLintTest {
+class UseFunctionTypeSyntaxForParametersTest extends FixProcessorLintTest
+    with WithNullSafetyLintMixin {
   @override
   FixKind get kind => DartFixKind.CONVERT_TO_GENERIC_FUNCTION_SYNTAX;
 
@@ -83,6 +84,24 @@
     await assertNoFix();
   }
 
+  Future<void> test_functionTypedParameter_nullable() async {
+    await resolveTestCode('''
+g(List<String> f()?) {}
+''');
+    await assertHasFix('''
+g(List<String> Function()? f) {}
+''');
+  }
+
+  Future<void> test_functionTypedParameter_requiredNamed() async {
+    await resolveTestCode('''
+g({required List<Object?> f()}) {}
+''');
+    await assertHasFix('''
+g({required List<Object?> Function() f}) {}
+''');
+  }
+
   Future<void> test_functionTypedParameter_returnType() async {
     await resolveTestCode('''
 g(String f(int x)) {}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart
index c8c9629..166007e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart
@@ -7,15 +7,40 @@
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'bulk/bulk_fix_processor.dart';
 import 'fix_processor.dart';
 
 void main() {
   defineReflectiveSuite(() {
+    defineReflectiveTests(RemoveUnnecessaryParenthesesBulkTest);
     defineReflectiveTests(RemoveUnnecessaryParenthesesTest);
   });
 }
 
 @reflectiveTest
+class RemoveUnnecessaryParenthesesBulkTest extends BulkFixProcessorTest {
+  @override
+  String get lintCode => LintNames.unnecessary_parenthesis;
+
+  Future<void> test_singleFile() async {
+    await resolveTestCode('''
+void f() {
+  (1);
+  (22);
+  (333);
+}
+''');
+    await assertHasFix('''
+void f() {
+  1;
+  22;
+  333;
+}
+''');
+  }
+}
+
+@reflectiveTest
 class RemoveUnnecessaryParenthesesTest extends FixProcessorLintTest {
   @override
   FixKind get kind => DartFixKind.REMOVE_UNNECESSARY_PARENTHESES;
@@ -23,25 +48,6 @@
   @override
   String get lintCode => LintNames.unnecessary_parenthesis;
 
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
-  Future<void> test_all() async {
-    await resolveTestCode('''
-void f() {
-  (1);
-  (22);
-  (333);
-}
-''');
-    var lintCode = await lintCodeByName(this.lintCode);
-    await assertHasFixAllFix(lintCode, '''
-void f() {
-  1;
-  22;
-  333;
-}
-''');
-  }
-
   Future<void> test_double_atInner() async {
     await resolveTestCode('''
 void f() {
@@ -63,7 +69,9 @@
 void f() {
   (42);
 }
-''', errorFilter: (e) => e.offset == testCode.indexOf('((42'));
+''',
+        errorFilter: (e) => e.offset == testCode.indexOf('((42'),
+        allowFixAllFixes: true);
   }
 
   Future<void> test_single() async {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart
index 0a630e7..0a2539b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart
@@ -124,14 +124,6 @@
 ''');
   }
 
-  Future<void> test_stringLiteral_variable_raw_single_notMulti() async {
-    await resolveTestCode('''
-var b = 'b';
-var c = r'a' + b;
-''');
-    await assertNoFix();
-  }
-
   Future<void> test_stringLiteral_variable_withEscapes() async {
     await resolveTestCode(r'''
 var b = 'b';
diff --git a/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart b/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart
index 03e4627..d610cce 100644
--- a/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart
@@ -32,6 +32,8 @@
     bool enableIndex = false,
     required List<String> includedPaths,
     List<String>? excludedPaths,
+    String? optionsFile,
+    String? packagesFile,
     PerformanceLog? performanceLog,
     ResourceProvider? resourceProvider,
     bool retainDataForTesting = false,
@@ -50,6 +52,8 @@
     var roots = contextLocator.locateRoots(
       includedPaths: includedPaths,
       excludedPaths: excludedPaths,
+      optionsFile: optionsFile,
+      packagesFile: packagesFile,
     );
     var fileContentOverlay = FileContentOverlay();
     for (var root in roots) {
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
index 7ec4bfb..4fcd8c8 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
@@ -77,6 +77,7 @@
     if (librarySummaryPaths != null) {
       options.librarySummaryPaths = librarySummaryPaths;
     }
+    options.defaultAnalysisOptionsFilePath = contextRoot.optionsFile?.path;
     options.defaultPackageFilePath = contextRoot.packagesFile?.path;
 
     old.ContextBuilder builder = old.ContextBuilder(
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_locator.dart b/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
index 6ad20a4..6612823 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
@@ -17,6 +17,7 @@
 import 'package:analyzer/src/task/options.dart';
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:analyzer/src/util/yaml.dart';
+import 'package:analyzer/src/workspace/basic.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:glob/glob.dart';
 import 'package:path/path.dart';
@@ -95,6 +96,7 @@
         folder,
         defaultOptionsFile: defaultOptionsFile,
         defaultPackagesFile: defaultPackagesFile,
+        defaultRootFolder: () => folder,
       );
 
       ContextRootImpl? root;
@@ -105,15 +107,14 @@
         }
       }
 
-      if (root == null) {
-        var rootFolder = _lowest2(location.rootFolder, folder)!;
-        root = _createContextRoot(
-          roots,
-          rootFolder: rootFolder,
-          optionsFile: location.optionsFile,
-          packagesFile: location.packagesFile,
-        );
-      }
+      root ??= _createContextRoot(
+        roots,
+        rootFolder: folder,
+        workspace: location.workspace,
+        optionsFile: location.optionsFile,
+        packagesFile: location.packagesFile,
+      );
+
       if (!root.isAnalyzed(folder.path)) {
         root.included.add(folder);
       }
@@ -134,13 +135,15 @@
         parent,
         defaultOptionsFile: defaultOptionsFile,
         defaultPackagesFile: defaultPackagesFile,
+        defaultRootFolder: () => _fileSystemRoot(parent),
       );
 
-      var rootFolder = location.rootFolder ?? _fileSystemRoot(parent);
+      var rootFolder = location.rootFolder;
       var root = rootMap.putIfAbsent(rootFolder, () {
         return _createContextRoot(
           roots,
           rootFolder: rootFolder,
+          workspace: location.workspace,
           optionsFile: location.optionsFile,
           packagesFile: location.packagesFile,
         );
@@ -173,6 +176,7 @@
     Folder parent, {
     required File? defaultOptionsFile,
     required File? defaultPackagesFile,
+    required Folder Function() defaultRootFolder,
   }) {
     File? optionsFile;
     Folder? optionsFolderToChooseRoot;
@@ -198,8 +202,24 @@
       packagesFolderToChooseRoot,
     );
 
+    var workspace = _createWorkspace(parent, packagesFile);
+    if (workspace is! BasicWorkspace) {
+      rootFolder = _lowest2(
+        rootFolder,
+        resourceProvider.getFolder(workspace.root),
+      );
+    }
+
+    if (rootFolder == null) {
+      rootFolder = defaultRootFolder();
+      if (workspace is BasicWorkspace) {
+        workspace = _createWorkspace(rootFolder, packagesFile);
+      }
+    }
+
     return _RootLocation(
       rootFolder: rootFolder,
+      workspace: workspace,
       optionsFile: optionsFile,
       packagesFile: packagesFile,
     );
@@ -208,10 +228,10 @@
   ContextRootImpl _createContextRoot(
     List<ContextRootImpl> roots, {
     required Folder rootFolder,
+    required Workspace workspace,
     required File? optionsFile,
     required File? packagesFile,
   }) {
-    var workspace = _createWorkspace(rootFolder, packagesFile);
     var root = ContextRootImpl(resourceProvider, rootFolder, workspace);
     root.packagesFile = packagesFile;
     root.optionsFile = optionsFile;
@@ -385,11 +405,11 @@
     List<Glob> patterns = [];
     File? optionsFile = root.optionsFile;
     if (optionsFile != null) {
-      var doc = AnalysisOptionsProvider(
-              root.workspace.createSourceFactory(null, null))
-          .getOptionsFromFile(optionsFile);
-
       try {
+        var doc = AnalysisOptionsProvider(
+                root.workspace.createSourceFactory(null, null))
+            .getOptionsFromFile(optionsFile);
+
         if (doc is YamlMap) {
           var analyzerOptions = getValue(doc, AnalyzerOptions.analyzer);
           if (analyzerOptions is YamlMap) {
@@ -462,14 +482,12 @@
       List<String> paths, List<Folder> folders, List<File> files) {
     for (String path in _uniqueSortedPaths(paths)) {
       Resource resource = resourceProvider.getResource(path);
-      if (resource.exists) {
-        if (resource is Folder) {
-          folders.add(resource);
-        } else if (resource is File) {
-          files.add(resource);
-        } else {
-          // Internal error: unhandled kind of resource.
-        }
+      if (resource is Folder) {
+        folders.add(resource);
+      } else if (resource is File) {
+        files.add(resource);
+      } else {
+        // Internal error: unhandled kind of resource.
       }
     }
   }
@@ -520,12 +538,14 @@
 }
 
 class _RootLocation {
-  final Folder? rootFolder;
+  final Folder rootFolder;
+  final Workspace workspace;
   final File? optionsFile;
   final File? packagesFile;
 
   _RootLocation({
     required this.rootFolder,
+    required this.workspace,
     required this.optionsFile,
     required this.packagesFile,
   });
diff --git a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
index a02ad16..fbbd960 100644
--- a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
@@ -32,6 +32,7 @@
     if (element is ExecutableElement) {
       InferenceContext.setType(node.arguments, element.type);
     }
+    node.typeArguments?.accept(_resolver);
     node.arguments?.accept(_resolver);
 
     var elementAnnotationImpl =
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 40726d1..658adba 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -355,9 +355,6 @@
   TypeSystemTypeOperations(this.typeSystem);
 
   @override
-  DartType get topType => typeSystem.objectQuestion;
-
-  @override
   TypeClassification classifyType(DartType type) {
     if (isSubtypeOf(type, typeSystem.typeProvider.objectType)) {
       return TypeClassification.nonNullable;
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index e05d2ad..816af4c 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -752,8 +752,8 @@
           node.methodName,
         );
       }
-      _resolver.flowAnalysis?.flow
-          ?.propertyGet(functionExpression, target, node.methodName.name);
+      _resolver.flowAnalysis?.flow?.propertyGet(
+          functionExpression, target, node.methodName.name, getterReturnType);
       functionExpression.staticType = targetType;
     }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index 5d0133f..23fcd9b 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -202,8 +202,10 @@
     if (hasRead) {
       var readLookup = _resolver.lexicalLookup(node: node, setter: false);
       readElementRequested = readLookup.requested;
-      if (readElementRequested is PropertyAccessorElement) {
-        _resolver.flowAnalysis?.flow?.thisOrSuperPropertyGet(node, node.name);
+      if (readElementRequested is PropertyAccessorElement &&
+          !readElementRequested.isStatic) {
+        _resolver.flowAnalysis?.flow?.thisOrSuperPropertyGet(
+            node, node.name, readElementRequested.returnType);
       }
       _resolver.checkReadOfNotAssignedLocalVariable(node, readElementRequested);
     }
@@ -372,7 +374,8 @@
       nameErrorEntity: propertyName,
     );
 
-    _resolver.flowAnalysis?.flow?.propertyGet(node, target, propertyName.name);
+    _resolver.flowAnalysis?.flow?.propertyGet(node, target, propertyName.name,
+        result.getter?.returnType ?? _typeSystem.typeProvider.dynamicType);
 
     if (hasRead && result.needsGetterError) {
       _errorReporter.reportErrorForNode(
@@ -621,8 +624,6 @@
 
     if (targetType is InterfaceTypeImpl) {
       if (hasRead) {
-        _resolver.flowAnalysis?.flow
-            ?.propertyGet(node, target, propertyName.name);
         var name = Name(_definingLibrary.source.uri, propertyName.name);
         readElement = _resolver.inheritance
             .getMember2(targetType.element, name, forSuper: true);
@@ -649,6 +650,11 @@
             );
           }
         }
+        _resolver.flowAnalysis?.flow?.propertyGet(
+            node,
+            target,
+            propertyName.name,
+            readElement?.returnType ?? _typeSystem.typeProvider.dynamicType);
       }
 
       if (hasWrite) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
index 99b1277..b189618 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
@@ -115,8 +115,20 @@
         }
       }
 
-      List<DiagnosticMessage> messages =
-          _resolver.computeWhyNotPromotedMessages(receiver, nameErrorEntity);
+      List<DiagnosticMessage> messages = [];
+      var flow = _resolver.flowAnalysis?.flow;
+      if (flow != null) {
+        if (receiver != null) {
+          messages = _resolver.computeWhyNotPromotedMessages(
+              receiver, nameErrorEntity, flow.whyNotPromoted(receiver));
+        } else {
+          var thisType = _resolver.thisType;
+          if (thisType != null) {
+            messages = _resolver.computeWhyNotPromotedMessages(receiver,
+                nameErrorEntity, flow.whyNotPromotedImplicitThis(thisType));
+          }
+        }
+      }
       _resolver.nullableDereferenceVerifier.report(
           receiverErrorNode, receiverType,
           errorCode: errorCode, arguments: [name], messages: messages);
diff --git a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
index 6044fab..87f07b8 100644
--- a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
+++ b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
@@ -67,7 +67,8 @@
 
     List<DiagnosticMessage>? messages;
     if (errorNode is Expression) {
-      messages = _resolver.computeWhyNotPromotedMessages(errorNode, errorNode);
+      messages = _resolver.computeWhyNotPromotedMessages(errorNode, errorNode,
+          _resolver.flowAnalysis?.flow?.whyNotPromoted(errorNode));
     }
     report(errorNode, receiverType, errorCode: errorCode, messages: messages);
     return true;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index fcdafed..581f6e1 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -514,9 +514,10 @@
   /// Computes the appropriate set of context messages to report along with an
   /// error that may have occurred because [receiver] was not type promoted.
   List<DiagnosticMessage> computeWhyNotPromotedMessages(
-      Expression? receiver, SyntacticEntity errorEntity) {
+      Expression? receiver,
+      SyntacticEntity errorEntity,
+      Map<DartType, NonPromotionReason>? whyNotPromoted) {
     List<DiagnosticMessage> messages = [];
-    var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(receiver);
     if (whyNotPromoted != null) {
       for (var entry in whyNotPromoted.entries) {
         var whyNotPromotedVisitor = _WhyNotPromotedVisitor(
@@ -526,10 +527,17 @@
         if (message != null) {
           if (flowAnalysis!.dataForTesting != null) {
             var nonPromotionReasonText = entry.value.shortName;
+            var args = <String>[];
             if (whyNotPromotedVisitor.propertyReference != null) {
               var id =
                   computeMemberId(whyNotPromotedVisitor.propertyReference!);
-              nonPromotionReasonText += '($id)';
+              args.add('target: $id');
+            }
+            if (whyNotPromotedVisitor.propertyType != null) {
+              args.add('type: ${whyNotPromotedVisitor.propertyType}');
+            }
+            if (args.isNotEmpty) {
+              nonPromotionReasonText += '(${args.join(', ')})';
             }
             flowAnalysis!.dataForTesting!.nonPromotionReasons[errorEntity] =
                 nonPromotionReasonText;
@@ -3338,7 +3346,7 @@
 class _WhyNotPromotedVisitor
     implements
         NonPromotionReasonVisitor<DiagnosticMessage?, AstNode, Expression,
-            PromotableElement> {
+            PromotableElement, DartType> {
   final Source source;
 
   final Expression? _receiver;
@@ -3349,6 +3357,8 @@
 
   PropertyAccessorElement? propertyReference;
 
+  DartType? propertyType;
+
   _WhyNotPromotedVisitor(
       this.source, this._receiver, this._errorEntity, this._dataForTesting);
 
@@ -3394,7 +3404,8 @@
   }
 
   @override
-  DiagnosticMessage? visitPropertyNotPromoted(PropertyNotPromoted reason) {
+  DiagnosticMessage? visitPropertyNotPromoted(
+      PropertyNotPromoted<DartType> reason) {
     var receiver = _receiver;
     Element? receiverElement;
     if (receiver is SimpleIdentifier) {
@@ -3408,6 +3419,7 @@
     }
     if (receiverElement is PropertyAccessorElement) {
       propertyReference = receiverElement;
+      propertyType = reason.staticType;
       return _contextMessageForProperty(receiverElement, reason.propertyName);
     } else {
       assert(receiverElement == null,
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 96b116d..9ca8628 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -285,8 +285,8 @@
 
   @override
   void visitSuperExpression(SuperExpression node) {
-    _resolver.flowAnalysis?.flow?.thisOrSuper(node);
     var thisType = _resolver.thisType;
+    _resolver.flowAnalysis?.flow?.thisOrSuper(node, thisType ?? _dynamicType);
     if (thisType == null ||
         node.thisOrAncestorOfType<ExtensionDeclaration>() != null) {
       // TODO(brianwilkerson) Report this error if it hasn't already been
@@ -306,8 +306,8 @@
   /// interface of the immediately enclosing class.</blockquote>
   @override
   void visitThisExpression(ThisExpression node) {
-    _resolver.flowAnalysis?.flow?.thisOrSuper(node);
     var thisType = _resolver.thisType;
+    _resolver.flowAnalysis?.flow?.thisOrSuper(node, thisType ?? _dynamicType);
     if (thisType == null) {
       // TODO(brianwilkerson) Report this error if it hasn't already been
       // reported.
diff --git a/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart b/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
index 50e73cb..c082771 100644
--- a/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
+++ b/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
@@ -55,6 +55,11 @@
     return newFile(path, content: content);
   }
 
+  File newBazelBuildFile(String directoryPath, String content) {
+    String path = join(directoryPath, file_paths.bazelBuild);
+    return newFile(path, content: content);
+  }
+
   File newDotPackagesFile(String directoryPath, {String content = ''}) {
     String path = join(directoryPath, file_paths.dotPackages);
     return newFile(path, content: content);
diff --git a/pkg/analyzer/lib/src/util/file_paths.dart b/pkg/analyzer/lib/src/util/file_paths.dart
index 6f8ade1..6420a36 100644
--- a/pkg/analyzer/lib/src/util/file_paths.dart
+++ b/pkg/analyzer/lib/src/util/file_paths.dart
@@ -31,6 +31,14 @@
 /// File name of pubspec files.
 const String pubspecYaml = 'pubspec.yaml';
 
+/// Converts the given [path] into absolute and normalized.
+String absoluteNormalized(p.Context pathContext, String path) {
+  path = path.trim();
+  path = pathContext.absolute(path);
+  path = pathContext.normalize(path);
+  return path;
+}
+
 /// Return `true` if [path] is an analysis options file.
 bool isAnalysisOptionsYaml(p.Context pathContext, String path) {
   return pathContext.basename(path) == analysisOptionsYaml;
diff --git a/pkg/analyzer/test/file_system/file_system_test_support.dart b/pkg/analyzer/test/file_system/file_system_test_support.dart
index 87c34b8..4004239 100644
--- a/pkg/analyzer/test/file_system/file_system_test_support.dart
+++ b/pkg/analyzer/test/file_system/file_system_test_support.dart
@@ -23,6 +23,10 @@
   /// A path to a folder within the [tempPath] that can be used by tests.
   String get defaultFolderPath;
 
+  /// Return `true` if the file system has support for symbolic links.
+  /// Windows until recently (Windows 10, 2016) did not have it.
+  bool get hasSymbolicLinkSupport;
+
   /// Return the resource provider to be used by the tests.
   ResourceProvider get provider;
 
@@ -139,6 +143,8 @@
   }
 
   test_exists_links_existing() {
+    if (!hasSymbolicLinkSupport) return;
+
     var a_path = join(tempPath, 'a.dart');
     var b_path = join(tempPath, 'b.dart');
 
@@ -153,6 +159,8 @@
   }
 
   test_exists_links_notExisting() {
+    if (!hasSymbolicLinkSupport) return;
+
     var a_path = join(tempPath, 'a.dart');
     var b_path = join(tempPath, 'b.dart');
 
@@ -306,6 +314,8 @@
   test_renameSync_notExisting();
 
   test_resolveSymbolicLinksSync_links_existing() {
+    if (!hasSymbolicLinkSupport) return;
+
     var a_path = join(tempPath, 'aaa', 'a.dart');
     var b_path = join(tempPath, 'bbb', 'b.dart');
 
@@ -317,6 +327,8 @@
   }
 
   test_resolveSymbolicLinksSync_links_existing2() {
+    if (!hasSymbolicLinkSupport) return;
+
     var a = join(tempPath, 'aaa', 'a.dart');
     var b = join(tempPath, 'bbb', 'b.dart');
     var c = join(tempPath, 'ccc', 'c.dart');
@@ -330,6 +342,8 @@
   }
 
   test_resolveSymbolicLinksSync_links_notExisting() {
+    if (!hasSymbolicLinkSupport) return;
+
     var a = join(tempPath, 'a.dart');
     var b = join(tempPath, 'b.dart');
 
@@ -527,6 +541,8 @@
   }
 
   test_exists_links_existing() {
+    if (!hasSymbolicLinkSupport) return;
+
     var foo_path = join(tempPath, 'foo');
     var bar_path = join(tempPath, 'bar');
 
@@ -541,6 +557,8 @@
   }
 
   test_exists_links_notExisting() {
+    if (!hasSymbolicLinkSupport) return;
+
     var foo_path = join(tempPath, 'foo');
     var bar_path = join(tempPath, 'bar');
 
@@ -664,6 +682,8 @@
   }
 
   test_getChildren_hasLink_file() {
+    if (!hasSymbolicLinkSupport) return;
+
     var a_path = join(tempPath, 'a.dart');
     var b_path = join(tempPath, 'b.dart');
 
@@ -682,6 +702,8 @@
   }
 
   test_getChildren_hasLink_folder() {
+    if (!hasSymbolicLinkSupport) return;
+
     var foo_path = join(tempPath, 'foo');
     var bar_path = join(tempPath, 'bar');
 
@@ -700,6 +722,8 @@
   }
 
   test_getChildren_isLink() {
+    if (!hasSymbolicLinkSupport) return;
+
     var foo_path = join(tempPath, 'foo');
     var bar_path = join(tempPath, 'bar');
     var foo_a_path = join(foo_path, 'a.dart');
@@ -778,6 +802,8 @@
   }
 
   test_resolveSymbolicLinksSync_links_existing() {
+    if (!hasSymbolicLinkSupport) return;
+
     var foo = join(tempPath, 'foo');
     var bar = join(tempPath, 'bar');
 
@@ -789,6 +815,8 @@
   }
 
   test_resolveSymbolicLinksSync_links_notExisting() {
+    if (!hasSymbolicLinkSupport) return;
+
     var foo = join(tempPath, 'foo');
     var bar = join(tempPath, 'bar');
 
diff --git a/pkg/analyzer/test/file_system/memory_file_system_test.dart b/pkg/analyzer/test/file_system/memory_file_system_test.dart
index c4a447c..34dc801 100644
--- a/pkg/analyzer/test/file_system/memory_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/memory_file_system_test.dart
@@ -48,6 +48,9 @@
   @override
   String get defaultFileContent => 'a';
 
+  @override
+  bool get hasSymbolicLinkSupport => true;
+
   /// Return the resource provider to be used by the tests.
   @override
   MemoryResourceProvider get provider => _provider ??= createProvider();
diff --git a/pkg/analyzer/test/file_system/physical_file_system_test.dart b/pkg/analyzer/test/file_system/physical_file_system_test.dart
index 9f871dd..3d33576 100644
--- a/pkg/analyzer/test/file_system/physical_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/physical_file_system_test.dart
@@ -48,6 +48,9 @@
   @override
   String get defaultFileContent => 'a';
 
+  @override
+  bool get hasSymbolicLinkSupport => !io.Platform.isWindows;
+
   /// Return the resource provider to be used by the tests.
   @override
   PhysicalResourceProvider get provider => _provider ??= createProvider();
diff --git a/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart b/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
index 2eac307..5869b63 100644
--- a/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
@@ -7,6 +7,10 @@
 import 'package:analyzer/src/dart/analysis/context_locator.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
+import 'package:analyzer/src/workspace/basic.dart';
+import 'package:analyzer/src/workspace/bazel.dart';
+import 'package:analyzer/src/workspace/pub.dart';
+import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -464,10 +468,106 @@
     expect(root.excludedPaths, isEmpty);
     expect(root.optionsFile, isNull);
     expect(root.packagesFile, isNull);
+    _assertBasicWorkspace(root.workspace, root.root.path);
 
     _assertAnalyzedFiles2(root, [testFile1, testFile2]);
   }
 
+  void test_locateRoots_multiple_files_bazel_differentWorkspaces() {
+    var workspacePath1 = '/home/workspace1';
+    var workspacePath2 = '/home/workspace2';
+    var pkgPath1 = '$workspacePath1/pkg1';
+    var pkgPath2 = '$workspacePath2/pkg2';
+
+    newFile('$workspacePath1/WORKSPACE');
+    newFile('$workspacePath2/WORKSPACE');
+    newBazelBuildFile(pkgPath1, '');
+    newBazelBuildFile(pkgPath2, '');
+
+    var file1 = newFile('$pkgPath1/lib/file1.dart');
+    var file2 = newFile('$pkgPath2/lib/file2.dart');
+
+    var roots = contextLocator.locateRoots(
+      includedPaths: [file1.path, file2.path],
+    );
+    expect(roots, hasLength(2));
+
+    var root1 = findRoot(roots, getFolder(workspacePath1));
+    expect(root1.includedPaths, unorderedEquals([file1.path]));
+    expect(root1.excludedPaths, isEmpty);
+    expect(root1.optionsFile, isNull);
+    expect(root1.packagesFile, isNull);
+    _assertBazelWorkspace(root1.workspace, workspacePath1);
+    _assertAnalyzedFiles2(root1, [file1]);
+
+    var root2 = findRoot(roots, getFolder(workspacePath2));
+    expect(root2.includedPaths, unorderedEquals([file2.path]));
+    expect(root2.excludedPaths, isEmpty);
+    expect(root2.optionsFile, isNull);
+    expect(root2.packagesFile, isNull);
+    _assertBazelWorkspace(root2.workspace, workspacePath2);
+    _assertAnalyzedFiles2(root2, [file2]);
+  }
+
+  void test_locateRoots_multiple_files_bazel_sameWorkspace_differentPackages() {
+    var workspacePath = '/home/workspace';
+    var fooPath = '$workspacePath/foo';
+    var barPath = '$workspacePath/bar';
+
+    newFile('$workspacePath/WORKSPACE');
+    newBazelBuildFile(fooPath, '');
+    newBazelBuildFile(barPath, '');
+
+    var fooFile = newFile('$fooPath/lib/foo.dart');
+    var barFile = newFile('$barPath/lib/bar.dart');
+
+    var roots = contextLocator.locateRoots(
+      includedPaths: [fooFile.path, barFile.path],
+    );
+    expect(roots, hasLength(1));
+
+    var root = findRoot(roots, getFolder(workspacePath));
+    expect(root.includedPaths, unorderedEquals([fooFile.path, barFile.path]));
+    expect(root.excludedPaths, isEmpty);
+    expect(root.optionsFile, isNull);
+    expect(root.packagesFile, isNull);
+    _assertBazelWorkspace(root.workspace, workspacePath);
+    _assertAnalyzedFiles2(root, [fooFile, barFile]);
+  }
+
+  void test_locateRoots_multiple_files_differentWorkspaces_pub() {
+    var rootPath = '/home';
+    var fooPath = '$rootPath/foo';
+    var barPath = '$rootPath/bar';
+
+    newPubspecYamlFile(fooPath, '');
+    newPubspecYamlFile(barPath, '');
+
+    var fooFile = newFile('$fooPath/lib/foo.dart');
+    var barFile = newFile('$barPath/lib/bar.dart');
+
+    var roots = contextLocator.locateRoots(
+      includedPaths: [fooFile.path, barFile.path],
+    );
+    expect(roots, hasLength(2));
+
+    var fooRoot = findRoot(roots, getFolder(fooPath));
+    expect(fooRoot.includedPaths, unorderedEquals([fooFile.path]));
+    expect(fooRoot.excludedPaths, isEmpty);
+    expect(fooRoot.optionsFile, isNull);
+    expect(fooRoot.packagesFile, isNull);
+    _assertPubWorkspace(fooRoot.workspace, fooPath);
+    _assertAnalyzedFiles2(fooRoot, [fooFile]);
+
+    var barRoot = findRoot(roots, getFolder(barPath));
+    expect(barRoot.includedPaths, unorderedEquals([barFile.path]));
+    expect(barRoot.excludedPaths, isEmpty);
+    expect(barRoot.optionsFile, isNull);
+    expect(barRoot.packagesFile, isNull);
+    _assertPubWorkspace(barRoot.workspace, barPath);
+    _assertAnalyzedFiles2(barRoot, [barFile]);
+  }
+
   void test_locateRoots_multiple_files_sameOptions_differentPackages() {
     var fooPackagesFile = newPackageConfigJsonFile('/home/foo');
     var barPackagesFile = newPackageConfigJsonFile('/home/bar');
@@ -830,6 +930,33 @@
     expect(outerRoot.packagesFile, outerPackagesFile);
   }
 
+  void test_locateRoots_options_hasError() {
+    Folder rootFolder = newFolder('/test/root');
+    File optionsFile = newAnalysisOptionsYamlFile('/test/root', content: '''
+analyzer:
+  exclude:
+    - **.g.dart
+analyzer:
+''');
+    File packagesFile = newDotPackagesFile('/test/root');
+
+    List<ContextRoot> roots =
+        contextLocator.locateRoots(includedPaths: [rootFolder.path]);
+    expect(roots, hasLength(1));
+
+    ContextRoot root = findRoot(roots, rootFolder);
+    expect(root.includedPaths, unorderedEquals([rootFolder.path]));
+    expect(root.excludedPaths, isEmpty);
+    expect(root.optionsFile, optionsFile);
+    expect(root.packagesFile, packagesFile);
+
+    // There is an error in the analysis_options.yaml, so it is ignored.
+    _assertAnalyzed(root, [
+      '/test/root//lib/a.dart',
+      '/test/root//lib/a.g.dart',
+    ]);
+  }
+
   void test_locateRoots_options_withExclude_someFiles() {
     Folder rootFolder = newFolder('/test/root');
     File optionsFile = newAnalysisOptionsYamlFile('/test/root', content: '''
@@ -1127,6 +1254,22 @@
     expect(package1Root.packagesFile, packagesFile);
   }
 
+  void test_locateRoots_single_file_notExisting() {
+    File optionsFile = newAnalysisOptionsYamlFile('/test');
+    File packagesFile = newDotPackagesFile('/test/root');
+    File testFile = getFile('/test/root/test.dart');
+
+    List<ContextRoot> roots =
+        contextLocator.locateRoots(includedPaths: [testFile.path]);
+    expect(roots, hasLength(1));
+
+    ContextRoot package1Root = findRoot(roots, testFile.parent2);
+    expect(package1Root.includedPaths, unorderedEquals([testFile.path]));
+    expect(package1Root.excludedPaths, isEmpty);
+    expect(package1Root.optionsFile, optionsFile);
+    expect(package1Root.packagesFile, packagesFile);
+  }
+
   void _assertAnalyzed(ContextRoot root, List<String> posixPathList) {
     for (var posixPath in posixPathList) {
       var path = convertPath(posixPath);
@@ -1150,6 +1293,16 @@
     _assertAnalyzedFiles(root, pathList);
   }
 
+  void _assertBasicWorkspace(Workspace _workspace, String root) {
+    var workspace = _workspace as BasicWorkspace;
+    expect(workspace.root, root);
+  }
+
+  void _assertBazelWorkspace(Workspace _workspace, String root) {
+    var workspace = _workspace as BazelWorkspace;
+    expect(workspace.root, root);
+  }
+
   void _assertNotAnalyzed(ContextRoot root, List<String> posixPathList) {
     for (var posixPath in posixPathList) {
       var path = convertPath(posixPath);
@@ -1157,6 +1310,11 @@
     }
   }
 
+  void _assertPubWorkspace(Workspace _workspace, String root) {
+    var workspace = _workspace as PubWorkspace;
+    expect(workspace.root, root);
+  }
+
   File _newPackageConfigFile(String directoryPath) {
     String path = join(
       directoryPath,
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 340a5a4..6778017 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -9755,7 +9755,7 @@
 
 ### type_argument_not_matching_bounds
 
-_'{0}' doesn't extend '{1}'._
+_'{0}' doesn't conform to the bound '{2}' of the type parameter '{1}'._
 
 #### Description
 
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index a37c423..a98502e 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -5,36 +5,28 @@
 import 'dart:io' as io;
 import 'dart:isolate';
 
-import 'package:analyzer/dart/analysis/context_locator.dart' as api;
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/sdk/build_sdk_summary.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:analyzer/src/context/builder.dart';
-import 'package:analyzer/src/context/context_root.dart';
-import 'package:analyzer/src/context/packages.dart';
+import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
-import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart'
-    as api;
+import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
-import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/analysis/results.dart';
-import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/interner.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/lint/linter.dart';
 import 'package:analyzer/src/lint/pub.dart';
 import 'package:analyzer/src/manifest/manifest_validator.dart';
 import 'package:analyzer/src/pubspec/pubspec_validator.dart';
-import 'package:analyzer/src/source/package_map_resolver.dart';
 import 'package:analyzer/src/source/path_filter.dart';
-import 'package:analyzer/src/summary/package_bundle_reader.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk;
 import 'package:analyzer/src/task/options.dart';
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:analyzer/src/util/yaml.dart';
@@ -51,6 +43,7 @@
 import 'package:linter/src/rules.dart' as linter;
 import 'package:meta/meta.dart';
 import 'package:path/path.dart' as path;
+import 'package:pub_semver/pub_semver.dart';
 import 'package:yaml/yaml.dart';
 
 /// Shared IO sink for standard error reporting.
@@ -71,6 +64,9 @@
   @override
   ContextCache contextCache;
 
+  _AnalysisContextProvider _analysisContextProvider;
+  DriverBasedAnalysisContext analysisContext;
+
   /// The driver that was most recently created by a call to [_analyzeAll], or
   /// `null` if [_analyzeAll] hasn't been called yet.
   @visibleForTesting
@@ -79,13 +75,6 @@
   /// The total number of source files loaded by an AnalysisContext.
   int _analyzedFileCount = 0;
 
-  /// If [analysisDriver] is not `null`, the [CommandLineOptions] that guided
-  /// its creation.
-  CommandLineOptions _previousOptions;
-
-  /// SDK instance.
-  DartSdk sdk;
-
   /// The resource provider used to access the file system.
   @override
   final ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
@@ -121,6 +110,8 @@
     // Parse commandline options.
     var options = CommandLineOptions.parse(resourceProvider, args);
 
+    _analysisContextProvider = _AnalysisContextProvider(resourceProvider);
+
     // Do analysis.
     if (options.buildMode) {
       var severity = await _buildModeAnalyze(options, sendPort);
@@ -172,12 +163,8 @@
     }
   }
 
-  Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async {
-    return await _analyzeAllImpl(options);
-  }
-
   /// Perform analysis according to the given [options].
-  Future<ErrorSeverity> _analyzeAllImpl(CommandLineOptions options) async {
+  Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async {
     if (!options.machineFormat) {
       var fileNames = options.sourceFiles.map((String file) {
         file = path.normalize(file);
@@ -192,6 +179,8 @@
       outSink.writeln("Analyzing ${fileNames.join(', ')}...");
     }
 
+    _verifyAnalysisOptionsFileExists(options);
+
     // These are used to do part file analysis across sources.
     var dartFiles = <String>{};
     var libraryFiles = <FileState>{};
@@ -228,16 +217,14 @@
       allResult = allResult.max(ErrorSeverity.ERROR);
     }
 
-    for (var sourcePath in options.sourceFiles) {
-      sourcePath = normalizePath(sourcePath);
+    var pathList = options.sourceFiles.map(normalizePath).toList();
+    _analysisContextProvider.setCommandLineOptions(options, pathList);
 
-      // Create a context, or re-use the previous one.
-      try {
-        _createContextAndAnalyze(options, sourcePath);
-      } on _DriverError catch (error) {
-        outSink.writeln(error.msg);
-        return ErrorSeverity.ERROR;
-      }
+    for (var sourcePath in pathList) {
+      _analysisContextProvider.configureForPath(sourcePath);
+      analysisContext = _analysisContextProvider.analysisContext;
+      analysisDriver = _analysisContextProvider.analysisDriver;
+      pathFilter = _analysisContextProvider.pathFilter;
 
       // Add all the files to be analyzed en masse to the context. Skip any
       // files that were added earlier (whether explicitly or implicitly) to
@@ -417,65 +404,6 @@
     }
   }
 
-  /// Decide on the appropriate method for resolving URIs based on the given
-  /// [options] and [customUrlMappings] settings, and return a
-  /// [SourceFactory] that has been configured accordingly.
-  /// When [includeSdkResolver] is `false`, return a temporary [SourceFactory]
-  /// for the purpose of resolved analysis options file `include:` directives.
-  /// In this situation, [analysisOptions] is ignored and can be `null`.
-  SourceFactory _chooseUriResolutionPolicy(
-      CommandLineOptions options,
-      Map<Folder, YamlMap> embedderMap,
-      _PackageInfo packageInfo,
-      SummaryDataStore summaryDataStore,
-      bool includeSdkResolver,
-      AnalysisOptions analysisOptions) {
-    UriResolver packageUriResolver;
-
-    if (packageInfo.packageMap != null) {
-      packageUriResolver = PackageMapUriResolver(
-        resourceProvider,
-        packageInfo.packageMap,
-      );
-    }
-
-    // Now, build our resolver list.
-    var resolvers = <UriResolver>[];
-
-    // 'dart:' URIs come first.
-
-    // Setup embedding.
-    if (includeSdkResolver) {
-      var embedderSdk = EmbedderSdk(
-        resourceProvider,
-        embedderMap,
-        languageVersion: sdk.languageVersion,
-      );
-      if (embedderSdk.libraryMap.size() == 0) {
-        // The embedder uri resolver has no mappings. Use the default Dart SDK
-        // uri resolver.
-        resolvers.add(DartUriResolver(sdk));
-      } else {
-        // The embedder uri resolver has mappings, use it instead of the default
-        // Dart SDK uri resolver.
-        resolvers.add(DartUriResolver(embedderSdk));
-      }
-    }
-
-    // Then package URIs from summaries.
-    resolvers.add(InSummaryUriResolver(resourceProvider, summaryDataStore));
-
-    // Then package URIs.
-    if (packageUriResolver != null) {
-      resolvers.add(packageUriResolver);
-    }
-
-    // Finally files.
-    resolvers.add(ResourceUriResolver(resourceProvider));
-
-    return SourceFactory(resolvers);
-  }
-
   /// Collect all analyzable files at [filePath], recursively if it's a
   /// directory, ignoring links.
   Iterable<io.File> _collectFiles(String filePath, AnalysisOptions options) {
@@ -503,130 +431,6 @@
     return files;
   }
 
-  /// Create an analysis driver that is prepared to analyze sources according
-  /// to the given [options], and store it in [analysisDriver].
-  void _createContextAndAnalyze(CommandLineOptions options, String source) {
-    // If not the same command-line options, clear cached information.
-    if (!_equalCommandLineOptions(_previousOptions, options)) {
-      _previousOptions = options;
-      contextCache = ContextCache(resourceProvider, options, verbosePrint);
-      analysisDriver = null;
-    }
-
-    var analysisOptions =
-        createAnalysisOptionsForCommandLineOptions(options, source);
-
-    // Store the [PathFilter] for this context to properly exclude files
-    pathFilter = PathFilter(getContextInfo(options, source).analysisRoot,
-        analysisOptions.excludePatterns);
-
-    // If we have the analysis driver, and the new analysis options are the
-    // same, we can reuse this analysis driver.
-    if (analysisDriver != null &&
-        AnalysisOptions.signaturesEqual(
-            analysisDriver.analysisOptions.signature,
-            analysisOptions.signature)) {
-      return;
-    }
-
-    // Set up logging.
-    if (options.log) {
-      AnalysisEngine.instance.instrumentationService = StdInstrumentation();
-    }
-
-    // Save stats from previous context before clobbering it.
-    if (analysisDriver != null) {
-      _analyzedFileCount += analysisDriver.knownFiles.length;
-    }
-
-    // Find package info.
-    var packageInfo = _findPackages(options);
-
-    // Process embedders.
-    var embedderMap = <Folder, YamlMap>{};
-    if (packageInfo.packageMap != null) {
-      var libFolder = packageInfo.packageMap['sky_engine']?.first;
-      if (libFolder != null) {
-        var locator = EmbedderYamlLocator.forLibFolder(libFolder);
-        embedderMap = locator.embedderYamls;
-      }
-    }
-
-    // No summaries in the presence of embedders.
-    var useSummaries = embedderMap.isEmpty;
-
-    if (!useSummaries && options.buildSummaryInputs.isNotEmpty) {
-      throw _DriverError('Summaries are not yet supported when using Flutter.');
-    }
-
-    // Read any input summaries.
-    var summaryDataStore = SummaryDataStore(
-        useSummaries ? options.buildSummaryInputs : <String>[]);
-
-    // Once options and embedders are processed, setup the SDK.
-    _setupSdk(options, analysisOptions);
-
-    // Choose a package resolution policy and a diet parsing policy based on
-    // the command-line options.
-    var sourceFactory = _chooseUriResolutionPolicy(options, embedderMap,
-        packageInfo, summaryDataStore, true, analysisOptions);
-
-    var log = PerformanceLog(null);
-    var scheduler = AnalysisDriverScheduler(log);
-
-    analysisDriver = AnalysisDriver(
-        scheduler,
-        log,
-        resourceProvider,
-        analysisDriverMemoryByteStore,
-        FileContentOverlay(),
-        ContextRoot(source, [], pathContext: resourceProvider.pathContext),
-        sourceFactory,
-        analysisOptions,
-        packages: packageInfo.packages);
-    analysisDriver.results.listen((_) {});
-    analysisDriver.exceptions.listen((_) {});
-    _setAnalysisDriverAnalysisContext(source);
-    scheduler.start();
-  }
-
-  _PackageInfo _findPackages(CommandLineOptions options) {
-    Packages packages;
-    Map<String, List<Folder>> packageMap;
-
-    if (options.packageConfigPath != null) {
-      var path = normalizePath(options.packageConfigPath);
-      try {
-        packages = parsePackagesFile(
-          resourceProvider,
-          resourceProvider.getFile(path),
-        );
-        packageMap = _getPackageMap(packages);
-      } catch (e) {
-        printAndFail('Unable to read package config data from $path: $e');
-      }
-    } else {
-      var cwd = resourceProvider.getResource(path.current);
-      // Look for .packages.
-      packages = findPackagesFrom(resourceProvider, cwd);
-      packageMap = _getPackageMap(packages);
-    }
-
-    return _PackageInfo(packages, packageMap);
-  }
-
-  Map<String, List<Folder>> _getPackageMap(Packages packages) {
-    if (packages == null) {
-      return null;
-    }
-
-    var packageMap = <String, List<Folder>>{};
-    for (var package in packages.packages) {
-      packageMap[package.name] = [package.libFolder];
-    }
-    return packageMap;
-  }
-
   /// Returns `true` if this relative path is a hidden directory.
   bool _isInHiddenDir(String relative) =>
       path.split(relative).any((part) => part.startsWith('.'));
@@ -640,41 +444,6 @@
     return analyzer.analyze(formatter);
   }
 
-  void _setAnalysisDriverAnalysisContext(String rootPath) {
-    var apiContextRoots = api.ContextLocator(
-      resourceProvider: resourceProvider,
-    ).locateRoots(
-      includedPaths: [rootPath],
-      excludedPaths: [],
-    );
-
-    if (apiContextRoots.isEmpty) {
-      return;
-    }
-
-    analysisDriver.configure(
-      analysisContext: api.DriverBasedAnalysisContext(
-        resourceProvider,
-        apiContextRoots.first,
-        analysisDriver,
-      ),
-    );
-  }
-
-  void _setupSdk(CommandLineOptions options, AnalysisOptions analysisOptions) {
-    if (sdk == null) {
-      if (options.dartSdkSummaryPath != null) {
-        sdk = SummaryBasedDartSdk(options.dartSdkSummaryPath, true);
-      } else {
-        var dartSdkPath = options.dartSdkPath;
-        sdk = FolderBasedDartSdk(
-          resourceProvider,
-          resourceProvider.getFolder(dartSdkPath),
-        );
-      }
-    }
-  }
-
   bool _shouldBeFatal(ErrorSeverity severity, CommandLineOptions options) {
     if (severity == ErrorSeverity.ERROR) {
       return true;
@@ -688,6 +457,16 @@
     }
   }
 
+  void _verifyAnalysisOptionsFileExists(CommandLineOptions options) {
+    var path = options.analysisOptionsFile;
+    if (path != null) {
+      if (!resourceProvider.getFile(path).exists) {
+        printAndFail('Options file not found: $path',
+            exitCode: ErrorSeverity.ERROR.ordinal);
+      }
+    }
+  }
+
   static void verbosePrint(String text) {
     outSink.writeln(text);
   }
@@ -708,6 +487,7 @@
         newOptions.lints == previous.lints &&
         _equalLists(
             newOptions.buildSummaryInputs, previous.buildSummaryInputs) &&
+        newOptions.defaultLanguageVersion == previous.defaultLanguageVersion &&
         newOptions.disableCacheFlushing == previous.disableCacheFlushing &&
         _equalLists(newOptions.enabledExperiments, previous.enabledExperiments);
   }
@@ -739,15 +519,114 @@
   }
 }
 
-class _DriverError implements Exception {
-  final String msg;
+class _AnalysisContextProvider {
+  final ResourceProvider _resourceProvider;
 
-  _DriverError(this.msg);
-}
+  CommandLineOptions _commandLineOptions;
+  List<String> _pathList;
 
-class _PackageInfo {
-  final Packages packages;
-  final Map<String, List<Folder>> packageMap;
+  final Map<Folder, DriverBasedAnalysisContext> _folderContexts = {};
+  AnalysisContextCollectionImpl _collection;
+  DriverBasedAnalysisContext _analysisContext;
 
-  _PackageInfo(this.packages, this.packageMap);
+  _AnalysisContextProvider(this._resourceProvider);
+
+  DriverBasedAnalysisContext get analysisContext {
+    return _analysisContext;
+  }
+
+  AnalysisDriver get analysisDriver {
+    return _analysisContext.driver;
+  }
+
+  /// TODO(scheglov) Use analyzedFiles()
+  PathFilter get pathFilter {
+    return PathFilter(analysisContext.contextRoot.root.path,
+        analysisContext.analysisOptions.excludePatterns);
+  }
+
+  void configureForPath(String path) {
+    var parentFolder = _resourceProvider.getFile(path).parent2;
+
+    // In batch mode we are given separate file paths to analyze.
+    // All files of a folder have the same configuration.
+    // So, reuse the corresponding analysis context.
+    _analysisContext = _folderContexts[parentFolder];
+    if (_analysisContext != null) {
+      return;
+    }
+
+    if (_collection != null) {
+      try {
+        _setContextForPath(path);
+        return;
+      } on StateError {
+        // The previous collection cannot analyze the path.
+        _collection = null;
+      }
+    }
+
+    _collection = AnalysisContextCollectionImpl(
+      byteStore: Driver.analysisDriverMemoryByteStore,
+      includedPaths: _pathList,
+      optionsFile: _commandLineOptions.analysisOptionsFile,
+      packagesFile: _commandLineOptions.packageConfigPath,
+      resourceProvider: _resourceProvider,
+      sdkPath: _commandLineOptions.dartSdkPath,
+    );
+
+    for (var _analysisContext in _collection.contexts) {
+      var analysisContext = _analysisContext as DriverBasedAnalysisContext;
+      _configureAnalysisOptionsFromCommandLineOptions(analysisContext);
+    }
+
+    _setContextForPath(path);
+    _folderContexts[parentFolder] = _analysisContext;
+  }
+
+  void setCommandLineOptions(
+    CommandLineOptions options,
+    List<String> pathList,
+  ) {
+    if (!Driver._equalCommandLineOptions(_commandLineOptions, options)) {
+      _folderContexts.clear();
+      _collection = null;
+      _analysisContext = null;
+    }
+    _commandLineOptions = options;
+    _pathList = pathList;
+  }
+
+  /// TODO(scheglov) Patch options before we create the driver.
+  void _configureAnalysisOptionsFromCommandLineOptions(
+    DriverBasedAnalysisContext analysisContext,
+  ) {
+    var analysisDriver = analysisContext.driver;
+    var optionsImpl = analysisDriver.analysisOptions as AnalysisOptionsImpl;
+
+    if (_commandLineOptions.enabledExperiments != null) {
+      optionsImpl.contextFeatures = FeatureSet.fromEnableFlags2(
+        sdkLanguageVersion: ExperimentStatus.currentVersion,
+        flags: _commandLineOptions.enabledExperiments,
+      );
+    }
+
+    if (_commandLineOptions.defaultLanguageVersion != null) {
+      var nonPackageLanguageVersion = Version.parse(
+        _commandLineOptions.defaultLanguageVersion + '.0',
+      );
+      optionsImpl.nonPackageLanguageVersion = nonPackageLanguageVersion;
+      optionsImpl.nonPackageFeatureSet = FeatureSet.latestLanguageVersion()
+          .restrictToVersion(nonPackageLanguageVersion);
+    }
+
+    analysisDriver.configure(
+      analysisOptions: optionsImpl,
+    );
+  }
+
+  void _setContextForPath(String path) {
+    var analysisContext = _collection.contextFor(path);
+    _analysisContext = analysisContext as DriverBasedAnalysisContext;
+  }
 }
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index cff668d..fc2ad75 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/src/command_line/arguments.dart';
 import 'package:analyzer/src/context/builder.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:analyzer/src/util/sdk.dart';
 import 'package:analyzer_cli/src/ansi.dart' as ansi;
 import 'package:analyzer_cli/src/driver.dart';
@@ -223,21 +224,21 @@
 
     // Check SDK.
     if (!options.buildModePersistentWorker) {
-      // Infer if unspecified.
-      options.dartSdkPath ??= getSdkPath(args);
-
       var sdkPath = options.dartSdkPath;
 
-      // Check that SDK is specified.
-      if (sdkPath == null) {
-        printAndFail('No Dart SDK found.');
-        return null; // Only reachable in testing.
-      }
       // Check that SDK is existing directory.
-      if (!(io.Directory(sdkPath)).existsSync()) {
-        printAndFail('Invalid Dart SDK path: $sdkPath');
-        return null; // Only reachable in testing.
+      if (sdkPath != null) {
+        if (!(io.Directory(sdkPath)).existsSync()) {
+          printAndFail('Invalid Dart SDK path: $sdkPath');
+          return null; // Only reachable in testing.
+        }
       }
+
+      // Infer if unspecified.
+      sdkPath ??= getSdkPath(args);
+
+      var pathContext = resourceProvider.pathContext;
+      options.dartSdkPath = file_paths.absoluteNormalized(pathContext, sdkPath);
     }
 
     // Build mode.
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index 249b959..6d818d6 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -992,15 +992,6 @@
     _expectUndefinedClassErrorsWithoutExclusions();
   }
 
-  Future<void>
-      test_analysisOptions_excludesRelativeToAnalysisOptions_inferred() async {
-    // By passing no options, and the path `lib`, it should discover the
-    // analysis_options above lib. The exclude is relative to the project, not
-    // the analyzed path, and it has to then understand that.
-    await drive('data/exclude_test_project/lib', options: null);
-    _expectUndefinedClassErrorsWithoutExclusions();
-  }
-
   Future<void> test_analyzeFilesInDifferentContexts() async {
     await driveMany([
       'data/linter_project/test_file.dart',
diff --git a/pkg/analyzer_cli/test/embedder_test.dart b/pkg/analyzer_cli/test/embedder_test.dart
index 8b554b0..3420843 100644
--- a/pkg/analyzer_cli/test/embedder_test.dart
+++ b/pkg/analyzer_cli/test/embedder_test.dart
@@ -4,7 +4,6 @@
 
 import 'dart:io';
 
-import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
@@ -41,19 +40,6 @@
       expect(exitCode, 0);
       expect(outSink.toString(), contains('No issues found'));
     }));
-
-    test('sdk setup', wrap(() async {
-      var testDir = path.join(testDirectory, 'data', 'embedder_client');
-      var driver = Driver();
-      await driver.start([
-        '--packages',
-        path.join(testDir, '_packages'),
-        path.join(testDir, 'embedder_yaml_user.dart')
-      ]);
-
-      var sdk = driver.sdk;
-      expect(sdk, const TypeMatcher<FolderBasedDartSdk>());
-    }));
   });
 }
 
diff --git a/pkg/dartdev/lib/src/analysis_server.dart b/pkg/dartdev/lib/src/analysis_server.dart
index 9b8340f..0f616f8 100644
--- a/pkg/dartdev/lib/src/analysis_server.dart
+++ b/pkg/dartdev/lib/src/analysis_server.dart
@@ -261,8 +261,6 @@
 
   int get length => json['location']['length'] as int;
 
-  String get messageSentenceFragment => trimEnd(message, '.');
-
   String get url => json['url'] as String;
 
   List<DiagnosticMessage> get contextMessages {
@@ -298,7 +296,7 @@
 
   @override
   String toString() => '${severity.toLowerCase()} • '
-      '$messageSentenceFragment at $file:$startLine:$startColumn • '
+      '$message • $file:$startLine:$startColumn • '
       '($code)';
 }
 
diff --git a/pkg/dartdev/lib/src/commands/analyze.dart b/pkg/dartdev/lib/src/commands/analyze.dart
index 5018dee..cbb4270 100644
--- a/pkg/dartdev/lib/src/commands/analyze.dart
+++ b/pkg/dartdev/lib/src/commands/analyze.dart
@@ -166,7 +166,8 @@
     io.Directory relativeToDir,
     bool verbose = false,
   }) {
-    final bullet = log.ansi.bullet;
+    final ansi = log.ansi;
+    final bullet = ansi.bullet;
 
     log.stdout('');
 
@@ -175,47 +176,43 @@
         : (dartdevUsageLineLength - _bodyIndentWidth);
 
     for (final AnalysisError error in errors) {
-      // error • Message ... at path.dart:line:col • (code)
-
-      var filePath = _relativePath(error.file, relativeToDir?.path);
       var severity = error.severity.toLowerCase().padLeft(_severityWidth);
       if (error.isError) {
-        severity = log.ansi.error(severity);
+        severity = ansi.error(severity);
+      }
+      var filePath = _relativePath(error.file, relativeToDir?.path);
+      var codeRef = error.code;
+      // If we're in verbose mode, write any error urls instead of error codes.
+      if (error.url != null && verbose) {
+        codeRef = error.url;
       }
 
+      // Emit "file:line:col * Error message. Correction (code)."
+      var message = ansi.emphasized('${error.message}');
+      if (error.correction != null) {
+        message += ' ${error.correction}';
+      }
+      var location = '$filePath:${error.startLine}:${error.startColumn}';
+      var output = '$location $bullet '
+          '$message $bullet '
+          '${ansi.green}$codeRef${ansi.none}';
+
+      // TODO(devoncarew): We need to take into account ansi color codes when
+      // performing line wrapping.
+      output = wrapText(output, width: wrapWidth);
       log.stdout(
         '$severity $bullet '
-        '${log.ansi.emphasized(error.messageSentenceFragment)} '
-        'at $filePath:${error.startLine}:${error.startColumn} $bullet '
-        '(${error.code})',
+        '${output.replaceAll('\n', '\n$_bodyIndent')}',
       );
 
-      if (verbose) {
-        for (var message in error.contextMessages) {
-          var contextPath = _relativePath(error.file, relativeToDir?.path);
-          var messageSentenceFragment = trimEnd(message.message, '.');
+      // Add any context messages as bullet list items.
+      for (var message in error.contextMessages) {
+        var contextPath = _relativePath(error.file, relativeToDir?.path);
+        var messageSentenceFragment = trimEnd(message.message, '.');
 
-          // Wrap longer context messages.
-          var contextMessage = wrapText(
-              '$messageSentenceFragment at '
-              '$contextPath:${message.line}:${message.column}',
-              width: wrapWidth);
-          log.stdout('$_bodyIndent'
-              '${contextMessage.replaceAll('\n', '\n$_bodyIndent')}');
-        }
-      }
-
-      if (error.correction != null) {
-        // Wrap longer correction messages.
-        var correction = wrapText(error.correction, width: wrapWidth);
-        log.stdout(
-            '$_bodyIndent${correction.replaceAll('\n', '\n$_bodyIndent')}');
-      }
-
-      if (verbose) {
-        if (error.url != null) {
-          log.stdout('$_bodyIndent${error.url}');
-        }
+        log.stdout('$_bodyIndent'
+            ' - $messageSentenceFragment at '
+            '$contextPath:${message.line}:${message.column}.');
       }
     }
 
diff --git a/pkg/dartdev/test/commands/analyze_test.dart b/pkg/dartdev/test/commands/analyze_test.dart
index 722951e..6d0709d 100644
--- a/pkg/dartdev/test/commands/analyze_test.dart
+++ b/pkg/dartdev/test/commands/analyze_test.dart
@@ -195,13 +195,11 @@
     expect(result.exitCode, 3);
     expect(result.stderr, isEmpty);
     var stdout = result.stdout;
-    expect(stdout, contains("The declaration of 'one' is on line 3 at "));
+    expect(stdout, contains("The declaration of 'one' is on line 3"));
     expect(
         stdout, contains('Try moving the declaration to before the first use'));
-    expect(
-        stdout,
-        contains(
-            'https://dart.dev/tools/diagnostic-messages#referenced_before_declaration'));
+    expect(stdout, contains('https://dart.dev'));
+    expect(stdout, contains('referenced_before_declaration'));
   });
 
   group('display mode', () {
@@ -227,10 +225,11 @@
       AnalyzeCommand.emitDefaultFormat(logger, errors);
 
       expect(logger.stderrBuffer, isEmpty);
-      expect(
-        logger.stdoutBuffer.toString().trim(),
-        contains('info - Foo bar baz at lib/test.dart:15:4 - (dead_code)'),
-      );
+      final stdout = logger.stdoutBuffer.toString().trim();
+      expect(stdout, contains('info'));
+      expect(stdout, contains('lib/test.dart:15:4'));
+      expect(stdout, contains('Foo bar baz.'));
+      expect(stdout, contains('dead_code'));
     });
 
     test('machine', () {
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index cb03daa..be077f9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -5707,7 +5707,8 @@
     ExpressionInferenceResult readResult = _computePropertyGet(
         node.fileOffset, receiver, receiverType, node.name, typeContext,
         isThisReceiver: node.receiver is ThisExpression);
-    inferrer.flowAnalysis.propertyGet(node, node.receiver, node.name.name);
+    inferrer.flowAnalysis.propertyGet(
+        node, node.receiver, node.name.name, readResult.inferredType);
     ExpressionInferenceResult expressionInferenceResult =
         inferrer.createNullAwareExpressionInferenceResult(
             readResult.inferredType, readResult.expression, nullAwareGuards);
@@ -5976,7 +5977,6 @@
   @override
   ExpressionInferenceResult visitSuperPropertyGet(
       SuperPropertyGet node, DartType typeContext) {
-    inferrer.flowAnalysis.thisOrSuperPropertyGet(node, node.name.name);
     if (node.interfaceTarget != null) {
       inferrer.instrumentation?.record(
           inferrer.uriForInstrumentation,
@@ -6164,7 +6164,7 @@
 
   ExpressionInferenceResult visitThisExpression(
       ThisExpression node, DartType typeContext) {
-    inferrer.flowAnalysis.thisOrSuper(node);
+    inferrer.flowAnalysis.thisOrSuper(node, inferrer.thisType);
     return new ExpressionInferenceResult(inferrer.thisType, node);
   }
 
@@ -6568,7 +6568,7 @@
     DartType promotedType;
     DartType declaredOrInferredType = variable.lateType ?? variable.type;
     if (isExtensionThis(variable)) {
-      inferrer.flowAnalysis.thisOrSuper(node);
+      inferrer.flowAnalysis.thisOrSuper(node, variable.type);
     } else if (inferrer.isNonNullableByDefault) {
       if (node.forNullGuardedAccess) {
         DartType nonNullableType = inferrer.computeNonNullable(variable.type);
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 a95ec85..2e20f55 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
@@ -274,9 +274,6 @@
   TypeOperationsCfe(this.typeEnvironment);
 
   @override
-  DartType get topType => typeEnvironment.objectNullableRawType;
-
-  @override
   TypeClassification classifyType(DartType type) {
     if (type == null) {
       // Note: this can happen during top-level inference.
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 b450ab3..d70f4c1 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
@@ -15,6 +15,7 @@
 import 'package:front_end/src/fasta/kernel/internal_ast.dart';
 import 'package:front_end/src/fasta/type_inference/type_demotion.dart';
 import 'package:front_end/src/testing/id_extractor.dart';
+import 'package:front_end/src/testing/id_testing_utils.dart';
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
@@ -317,9 +318,18 @@
         LocatedMessage message = entry.value.accept(whyNotPromotedVisitor);
         if (dataForTesting != null) {
           String nonPromotionReasonText = entry.value.shortName;
+          List<String> args = <String>[];
           if (whyNotPromotedVisitor.propertyReference != null) {
             Id id = computeMemberId(whyNotPromotedVisitor.propertyReference);
-            nonPromotionReasonText += '($id)';
+            args.add('target: $id');
+          }
+          if (whyNotPromotedVisitor.propertyType != null) {
+            String typeText = typeToText(whyNotPromotedVisitor.propertyType,
+                TypeRepresentation.analyzerNonNullableByDefault);
+            args.add('type: $typeText');
+          }
+          if (args.isNotEmpty) {
+            nonPromotionReasonText += '(${args.join(', ')})';
           }
           dataForTesting.flowAnalysisResult.nonPromotionReasons[expression] =
               nonPromotionReasonText;
@@ -3393,7 +3403,7 @@
           resultType: calleeType, interfaceTarget: originalTarget)
         ..fileOffset = fileOffset;
       flowAnalysis.propertyGet(
-          originalPropertyGet, originalReceiver, originalName.name);
+          originalPropertyGet, originalReceiver, originalName.name, calleeType);
     } else {
       originalPropertyGet =
           new PropertyGet(originalReceiver, originalName, originalTarget)
@@ -3766,6 +3776,8 @@
     if (member is Procedure && member.kind == ProcedureKind.Method) {
       return instantiateTearOff(inferredType, typeContext, expression);
     }
+    flowAnalysis.thisOrSuperPropertyGet(
+        expression, expression.name.name, inferredType);
     return new ExpressionInferenceResult(inferredType, expression);
   }
 
@@ -5007,13 +5019,15 @@
 class _WhyNotPromotedVisitor
     implements
         NonPromotionReasonVisitor<LocatedMessage, Node, Expression,
-            VariableDeclaration> {
+            VariableDeclaration, DartType> {
   final TypeInferrerImpl inferrer;
 
   final Expression receiver;
 
   Member propertyReference;
 
+  DartType propertyType;
+
   _WhyNotPromotedVisitor(this.inferrer, this.receiver);
 
   @override
@@ -5055,6 +5069,7 @@
     }
     if (member != null) {
       propertyReference = member;
+      propertyType = reason.staticType;
       return templateFieldNotPromoted
           .withArguments(reason.propertyName)
           .withLocation(member.fileUri, member.fileOffset, noLength);
diff --git a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
index 0f9328a..4c776c8 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
@@ -21,14 +21,6 @@
       this._typeSystem, this._variableRepository, this._graph);
 
   @override
-  DecoratedType get topType {
-    // This is only needed for explaining to the user why fields aren't
-    // promoted, functionality of flow analysis that we don't take advantage of
-    // during migration.  So this method should never be called.
-    throw StateError('Unexpected call to topType');
-  }
-
-  @override
   TypeClassification classifyType(DecoratedType type) {
     if (type.type.isDartCoreNull) {
       return TypeClassification.nullOrEquivalent;
diff --git a/pkg/vm_service/lib/src/snapshot_graph.dart b/pkg/vm_service/lib/src/snapshot_graph.dart
index e51c36b..14e5818 100644
--- a/pkg/vm_service/lib/src/snapshot_graph.dart
+++ b/pkg/vm_service/lib/src/snapshot_graph.dart
@@ -194,7 +194,7 @@
   /// Data associated with this object.
   dynamic get data => _data;
 
-  /// A list of indicies into [HeapSnapshotGraph.objects].
+  /// A list of indices into [HeapSnapshotGraph.objects].
   List<int> get references => _references;
 
   /// The identity hash code of this object.
diff --git a/pkg/vm_service/test/rpc_error_test.dart b/pkg/vm_service/test/rpc_error_test.dart
index e6b5df5..c9cf1be 100644
--- a/pkg/vm_service/test/rpc_error_test.dart
+++ b/pkg/vm_service/test/rpc_error_test.dart
@@ -9,7 +9,7 @@
 
 var tests = <VMTest>[
   (VmService vm) async {
-    // Invoke a non-existant RPC.
+    // Invoke a non-existent RPC.
     try {
       final res = await vm.callMethod('foo');
       fail('Expected RPCError, got $res');
diff --git a/pkg/wasm/lib/src/function.dart b/pkg/wasm/lib/src/function.dart
index 82f07b8..8cff328 100644
--- a/pkg/wasm/lib/src/function.dart
+++ b/pkg/wasm/lib/src/function.dart
@@ -13,17 +13,16 @@
   Pointer<WasmerFunc> _func;
   List<int> _argTypes;
   int _returnType;
-  Pointer<WasmerValVec> _args = allocate<WasmerValVec>();
-  Pointer<WasmerValVec> _results = allocate<WasmerValVec>();
+  Pointer<WasmerValVec> _args = calloc<WasmerValVec>();
+  Pointer<WasmerValVec> _results = calloc<WasmerValVec>();
 
   WasmFunction(this._name, this._func, this._argTypes, this._returnType) {
     _args.ref.length = _argTypes.length;
-    _args.ref.data = _argTypes.length == 0
-        ? nullptr
-        : allocate<WasmerVal>(count: _argTypes.length);
+    _args.ref.data =
+        _argTypes.length == 0 ? nullptr : calloc<WasmerVal>(_argTypes.length);
     _results.ref.length = _returnType == WasmerValKindVoid ? 0 : 1;
     _results.ref.data =
-        _returnType == WasmerValKindVoid ? nullptr : allocate<WasmerVal>();
+        _returnType == WasmerValKindVoid ? nullptr : calloc<WasmerVal>();
     for (var i = 0; i < _argTypes.length; ++i) {
       _args.ref.data[i].kind = _argTypes[i];
     }
diff --git a/pkg/wasm/lib/src/module.dart b/pkg/wasm/lib/src/module.dart
index b06abb8..6eb4e12 100644
--- a/pkg/wasm/lib/src/module.dart
+++ b/pkg/wasm/lib/src/module.dart
@@ -62,7 +62,7 @@
 
 void _wasmFnImportFinalizer(Pointer<_WasmFnImport> imp) {
   _wasmFnImportToFn.remove(imp.address);
-  free(imp);
+  calloc.free(imp);
 }
 
 final _wasmFnImportTrampolineNative = Pointer.fromFunction<
@@ -115,15 +115,14 @@
   WasmModule _module;
   late List<WasmImportDescriptor> _importDescs;
   Map<String, int> _importIndex;
-  Pointer<WasmerExternVec> _imports = allocate<WasmerExternVec>();
+  Pointer<WasmerExternVec> _imports = calloc<WasmerExternVec>();
   Pointer<WasmerWasiEnv> _wasiEnv = nullptr;
   Object _importOwner = Object();
 
   WasmInstanceBuilder(this._module) : _importIndex = {} {
     _importDescs = WasmRuntime().importDescriptors(_module._module);
     _imports.ref.length = _importDescs.length;
-    _imports.ref.data =
-        allocate<Pointer<WasmerExtern>>(count: _importDescs.length);
+    _imports.ref.data = calloc<Pointer<WasmerExtern>>(_importDescs.length);
     for (var i = 0; i < _importDescs.length; ++i) {
       var imp = _importDescs[i];
       _importIndex["${imp.moduleName}::${imp.name}"] = i;
@@ -166,7 +165,7 @@
 
     var argTypes = runtime.getArgTypes(imp.funcType);
     var returnType = runtime.getReturnType(imp.funcType);
-    var wasmFnImport = allocate<_WasmFnImport>();
+    var wasmFnImport = calloc<_WasmFnImport>();
     wasmFnImport.ref.returnType = returnType;
     wasmFnImport.ref.store = _module._store;
     _wasmFnImportToFn[wasmFnImport.address] = fn;
diff --git a/pkg/wasm/lib/src/runtime.dart b/pkg/wasm/lib/src/runtime.dart
index 777c6dc..c543752 100644
--- a/pkg/wasm/lib/src/runtime.dart
+++ b/pkg/wasm/lib/src/runtime.dart
@@ -435,18 +435,18 @@
 
   Pointer<WasmerModule> compile(
       Object owner, Pointer<WasmerStore> store, Uint8List data) {
-    var dataPtr = allocate<Uint8>(count: data.length);
+    var dataPtr = calloc<Uint8>(data.length);
     for (int i = 0; i < data.length; ++i) {
       dataPtr[i] = data[i];
     }
-    var dataVec = allocate<WasmerByteVec>();
+    var dataVec = calloc<WasmerByteVec>();
     dataVec.ref.data = dataPtr;
     dataVec.ref.length = data.length;
 
     var modulePtr = _module_new(store, dataVec);
 
-    free(dataPtr);
-    free(dataVec);
+    calloc.free(dataPtr);
+    calloc.free(dataVec);
 
     _checkNotEqual(modulePtr, nullptr, "Wasm module compile failed.");
     _set_finalizer_for_module(owner, modulePtr);
@@ -454,7 +454,7 @@
   }
 
   List<WasmExportDescriptor> exportDescriptors(Pointer<WasmerModule> module) {
-    var exportsVec = allocate<WasmerExporttypeVec>();
+    var exportsVec = calloc<WasmerExporttypeVec>();
     _module_exports(module, exportsVec);
     var exps = <WasmExportDescriptor>[];
     for (var i = 0; i < exportsVec.ref.length; ++i) {
@@ -467,12 +467,12 @@
       exps.add(WasmExportDescriptor(
           kind, _exporttype_name(exp).ref.toString(), fnType));
     }
-    free(exportsVec);
+    calloc.free(exportsVec);
     return exps;
   }
 
   List<WasmImportDescriptor> importDescriptors(Pointer<WasmerModule> module) {
-    var importsVec = allocate<WasmerImporttypeVec>();
+    var importsVec = calloc<WasmerImporttypeVec>();
     _module_imports(module, importsVec);
     var imps = <WasmImportDescriptor>[];
     for (var i = 0; i < importsVec.ref.length; ++i) {
@@ -488,7 +488,7 @@
           _importtype_name(imp).ref.toString(),
           fnType));
     }
-    free(importsVec);
+    calloc.free(importsVec);
     return imps;
   }
 
@@ -504,11 +504,11 @@
         traps.remove(entry);
         throw entry.exception;
       } else {
-        var trapMessage = allocate<WasmerByteVec>();
+        var trapMessage = calloc<WasmerByteVec>();
         _trap_message(trap, trapMessage);
         var message = "Wasm trap when calling $source: ${trapMessage.ref}";
         _byte_vec_delete(trapMessage);
-        free(trapMessage);
+        calloc.free(trapMessage);
         _trap_delete(trap);
         throw Exception(message);
       }
@@ -517,11 +517,11 @@
 
   Pointer<WasmerInstance> instantiate(Object owner, Pointer<WasmerStore> store,
       Pointer<WasmerModule> module, Pointer<WasmerExternVec> imports) {
-    var trap = allocate<Pointer<WasmerTrap>>();
+    var trap = calloc<Pointer<WasmerTrap>>();
     trap.value = nullptr;
     var inst = _instance_new(store, module, imports, trap);
     maybeThrowTrap(trap.value, "module initialization function");
-    free(trap);
+    calloc.free(trap);
     _checkNotEqual(inst, nullptr, "Wasm module instantiation failed.");
     _set_finalizer_for_instance(owner, inst);
     return inst;
@@ -529,14 +529,14 @@
 
   // Clean up the exports after use, with deleteExports.
   Pointer<WasmerExternVec> exports(Pointer<WasmerInstance> instancePtr) {
-    var exports = allocate<WasmerExternVec>();
+    var exports = calloc<WasmerExternVec>();
     _instance_exports(instancePtr, exports);
     return exports;
   }
 
   void deleteExports(Pointer<WasmerExternVec> exports) {
     _extern_vec_delete(exports);
-    free(exports);
+    calloc.free(exports);
   }
 
   int externKind(Pointer<WasmerExtern> extern) {
@@ -585,11 +585,11 @@
 
   Pointer<WasmerMemory> newMemory(
       Object owner, Pointer<WasmerStore> store, int pages, int? maxPages) {
-    var limPtr = allocate<WasmerLimits>();
+    var limPtr = calloc<WasmerLimits>();
     limPtr.ref.min = pages;
     limPtr.ref.max = maxPages ?? wasm_limits_max_default;
     var memType = _memorytype_new(limPtr);
-    free(limPtr);
+    calloc.free(limPtr);
     _checkNotEqual(memType, nullptr, "Failed to create memory type.");
     _set_finalizer_for_memorytype(owner, memType);
     var memory = _checkNotEqual(
@@ -626,13 +626,13 @@
   }
 
   Pointer<WasmerTrap> newTrap(Pointer<WasmerStore> store, dynamic exception) {
-    var msg = allocate<WasmerByteVec>();
-    msg.ref.data = allocate<Uint8>();
+    var msg = calloc<WasmerByteVec>();
+    msg.ref.data = calloc<Uint8>();
     msg.ref.data[0] = 0;
     msg.ref.length = 0;
     var trap = _trap_new(store, msg);
-    free(msg.ref.data);
-    free(msg);
+    calloc.free(msg.ref.data);
+    calloc.free(msg);
     _checkNotEqual(trap, nullptr, "Failed to create trap.");
     var entry = _WasmTrapsEntry(exception);
     _set_finalizer_for_trap(entry, trap);
@@ -641,10 +641,10 @@
   }
 
   Pointer<WasmerWasiConfig> newWasiConfig() {
-    var name = allocate<Uint8>();
+    var name = calloc<Uint8>();
     name[0] = 0;
     var config = _wasi_config_new(name);
-    free(name);
+    calloc.free(name);
     return _checkNotEqual(config, nullptr, "Failed to create WASI config.");
   }
 
@@ -682,10 +682,10 @@
 
   String _getLastError() {
     var length = _wasmer_last_error_length();
-    var buf = allocate<Uint8>(count: length);
+    var buf = calloc<Uint8>(length);
     _wasmer_last_error_message(buf, length);
     String message = utf8.decode(buf.asTypedList(length));
-    free(buf);
+    calloc.free(buf);
     return message;
   }
 
@@ -707,7 +707,7 @@
   static final int _bufferLength = 1024;
   Pointer<WasmerWasiEnv> _env;
   Function _reader;
-  Pointer<Uint8> _buf = allocate<Uint8>(count: _bufferLength);
+  Pointer<Uint8> _buf = calloc<Uint8>(_bufferLength);
   int _length = 0;
   _WasiStreamIterator(this._env, this._reader) {}
 
diff --git a/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py b/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py
index 4feda0e..a6877a7 100755
--- a/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py
+++ b/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py
@@ -88,7 +88,7 @@
 
 
 opaqueTypeTemplate = '''// %s_t
-class Wasmer%s extends Struct {}'''
+class Wasmer%s extends Opaque {}'''
 
 vecTypeTemplate = '''// %s_vec_t
 class Wasmer%sVec extends Struct {
diff --git a/pkg/wasm/lib/src/tools/runtime_template.dart b/pkg/wasm/lib/src/tools/runtime_template.dart
index 385004f..2757504 100644
--- a/pkg/wasm/lib/src/tools/runtime_template.dart
+++ b/pkg/wasm/lib/src/tools/runtime_template.dart
@@ -126,18 +126,18 @@
 
   Pointer<WasmerModule> compile(
       Object owner, Pointer<WasmerStore> store, Uint8List data) {
-    var dataPtr = allocate<Uint8>(count: data.length);
+    var dataPtr = calloc<Uint8>(data.length);
     for (int i = 0; i < data.length; ++i) {
       dataPtr[i] = data[i];
     }
-    var dataVec = allocate<WasmerByteVec>();
+    var dataVec = calloc<WasmerByteVec>();
     dataVec.ref.data = dataPtr;
     dataVec.ref.length = data.length;
 
     var modulePtr = _module_new(store, dataVec);
 
-    free(dataPtr);
-    free(dataVec);
+    calloc.free(dataPtr);
+    calloc.free(dataVec);
 
     _checkNotEqual(modulePtr, nullptr, "Wasm module compile failed.");
     _set_finalizer_for_module(owner, modulePtr);
@@ -145,7 +145,7 @@
   }
 
   List<WasmExportDescriptor> exportDescriptors(Pointer<WasmerModule> module) {
-    var exportsVec = allocate<WasmerExporttypeVec>();
+    var exportsVec = calloc<WasmerExporttypeVec>();
     _module_exports(module, exportsVec);
     var exps = <WasmExportDescriptor>[];
     for (var i = 0; i < exportsVec.ref.length; ++i) {
@@ -158,12 +158,12 @@
       exps.add(WasmExportDescriptor(
           kind, _exporttype_name(exp).ref.toString(), fnType));
     }
-    free(exportsVec);
+    calloc.free(exportsVec);
     return exps;
   }
 
   List<WasmImportDescriptor> importDescriptors(Pointer<WasmerModule> module) {
-    var importsVec = allocate<WasmerImporttypeVec>();
+    var importsVec = calloc<WasmerImporttypeVec>();
     _module_imports(module, importsVec);
     var imps = <WasmImportDescriptor>[];
     for (var i = 0; i < importsVec.ref.length; ++i) {
@@ -179,7 +179,7 @@
           _importtype_name(imp).ref.toString(),
           fnType));
     }
-    free(importsVec);
+    calloc.free(importsVec);
     return imps;
   }
 
@@ -195,11 +195,11 @@
         traps.remove(entry);
         throw entry.exception;
       } else {
-        var trapMessage = allocate<WasmerByteVec>();
+        var trapMessage = calloc<WasmerByteVec>();
         _trap_message(trap, trapMessage);
         var message = "Wasm trap when calling $source: ${trapMessage.ref}";
         _byte_vec_delete(trapMessage);
-        free(trapMessage);
+        calloc.free(trapMessage);
         _trap_delete(trap);
         throw Exception(message);
       }
@@ -208,11 +208,11 @@
 
   Pointer<WasmerInstance> instantiate(Object owner, Pointer<WasmerStore> store,
       Pointer<WasmerModule> module, Pointer<WasmerExternVec> imports) {
-    var trap = allocate<Pointer<WasmerTrap>>();
+    var trap = calloc<Pointer<WasmerTrap>>();
     trap.value = nullptr;
     var inst = _instance_new(store, module, imports, trap);
     maybeThrowTrap(trap.value, "module initialization function");
-    free(trap);
+    calloc.free(trap);
     _checkNotEqual(inst, nullptr, "Wasm module instantiation failed.");
     _set_finalizer_for_instance(owner, inst);
     return inst;
@@ -220,14 +220,14 @@
 
   // Clean up the exports after use, with deleteExports.
   Pointer<WasmerExternVec> exports(Pointer<WasmerInstance> instancePtr) {
-    var exports = allocate<WasmerExternVec>();
+    var exports = calloc<WasmerExternVec>();
     _instance_exports(instancePtr, exports);
     return exports;
   }
 
   void deleteExports(Pointer<WasmerExternVec> exports) {
     _extern_vec_delete(exports);
-    free(exports);
+    calloc.free(exports);
   }
 
   int externKind(Pointer<WasmerExtern> extern) {
@@ -276,11 +276,11 @@
 
   Pointer<WasmerMemory> newMemory(
       Object owner, Pointer<WasmerStore> store, int pages, int? maxPages) {
-    var limPtr = allocate<WasmerLimits>();
+    var limPtr = calloc<WasmerLimits>();
     limPtr.ref.min = pages;
     limPtr.ref.max = maxPages ?? wasm_limits_max_default;
     var memType = _memorytype_new(limPtr);
-    free(limPtr);
+    calloc.free(limPtr);
     _checkNotEqual(memType, nullptr, "Failed to create memory type.");
     _set_finalizer_for_memorytype(owner, memType);
     var memory = _checkNotEqual(
@@ -317,13 +317,13 @@
   }
 
   Pointer<WasmerTrap> newTrap(Pointer<WasmerStore> store, dynamic exception) {
-    var msg = allocate<WasmerByteVec>();
-    msg.ref.data = allocate<Uint8>();
+    var msg = calloc<WasmerByteVec>();
+    msg.ref.data = calloc<Uint8>();
     msg.ref.data[0] = 0;
     msg.ref.length = 0;
     var trap = _trap_new(store, msg);
-    free(msg.ref.data);
-    free(msg);
+    calloc.free(msg.ref.data);
+    calloc.free(msg);
     _checkNotEqual(trap, nullptr, "Failed to create trap.");
     var entry = _WasmTrapsEntry(exception);
     _set_finalizer_for_trap(entry, trap);
@@ -332,10 +332,10 @@
   }
 
   Pointer<WasmerWasiConfig> newWasiConfig() {
-    var name = allocate<Uint8>();
+    var name = calloc<Uint8>();
     name[0] = 0;
     var config = _wasi_config_new(name);
-    free(name);
+    calloc.free(name);
     return _checkNotEqual(config, nullptr, "Failed to create WASI config.");
   }
 
@@ -373,10 +373,10 @@
 
   String _getLastError() {
     var length = _wasmer_last_error_length();
-    var buf = allocate<Uint8>(count: length);
+    var buf = calloc<Uint8>(length);
     _wasmer_last_error_message(buf, length);
     String message = utf8.decode(buf.asTypedList(length));
-    free(buf);
+    calloc.free(buf);
     return message;
   }
 
@@ -398,7 +398,7 @@
   static final int _bufferLength = 1024;
   Pointer<WasmerWasiEnv> _env;
   Function _reader;
-  Pointer<Uint8> _buf = allocate<Uint8>(count: _bufferLength);
+  Pointer<Uint8> _buf = calloc<Uint8>(_bufferLength);
   int _length = 0;
   _WasiStreamIterator(this._env, this._reader) {}
 
diff --git a/pkg/wasm/lib/src/wasmer_api.dart b/pkg/wasm/lib/src/wasmer_api.dart
index b95cf9a..8a28af1 100644
--- a/pkg/wasm/lib/src/wasmer_api.dart
+++ b/pkg/wasm/lib/src/wasmer_api.dart
@@ -116,52 +116,52 @@
 const int wasm_limits_max_default = 0xffffffff;
 
 // wasm_engine_t
-class WasmerEngine extends Struct {}
+class WasmerEngine extends Opaque {}
 
 // wasm_exporttype_t
-class WasmerExporttype extends Struct {}
+class WasmerExporttype extends Opaque {}
 
 // wasm_extern_t
-class WasmerExtern extends Struct {}
+class WasmerExtern extends Opaque {}
 
 // wasm_externtype_t
-class WasmerExterntype extends Struct {}
+class WasmerExterntype extends Opaque {}
 
 // wasm_func_t
-class WasmerFunc extends Struct {}
+class WasmerFunc extends Opaque {}
 
 // wasm_functype_t
-class WasmerFunctype extends Struct {}
+class WasmerFunctype extends Opaque {}
 
 // wasm_importtype_t
-class WasmerImporttype extends Struct {}
+class WasmerImporttype extends Opaque {}
 
 // wasm_instance_t
-class WasmerInstance extends Struct {}
+class WasmerInstance extends Opaque {}
 
 // wasm_memory_t
-class WasmerMemory extends Struct {}
+class WasmerMemory extends Opaque {}
 
 // wasm_memorytype_t
-class WasmerMemorytype extends Struct {}
+class WasmerMemorytype extends Opaque {}
 
 // wasm_module_t
-class WasmerModule extends Struct {}
+class WasmerModule extends Opaque {}
 
 // wasm_store_t
-class WasmerStore extends Struct {}
+class WasmerStore extends Opaque {}
 
 // wasm_trap_t
-class WasmerTrap extends Struct {}
+class WasmerTrap extends Opaque {}
 
 // wasm_valtype_t
-class WasmerValtype extends Struct {}
+class WasmerValtype extends Opaque {}
 
 // wasi_config_t
-class WasmerWasiConfig extends Struct {}
+class WasmerWasiConfig extends Opaque {}
 
 // wasi_env_t
-class WasmerWasiEnv extends Struct {}
+class WasmerWasiEnv extends Opaque {}
 
 // wasm_byte_vec_t
 class WasmerByteVec extends Struct {
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 503fa52..91c5e85 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -205,15 +205,10 @@
 }
 
 static int CountLeadingZeros(uint64_t value, int width) {
-  ASSERT((width == 32) || (width == 64));
-  if (value == 0) {
-    return width;
-  }
-  int count = 0;
-  do {
-    count++;
-  } while (value >>= 1);
-  return width - count;
+  if (width == 64) return Utils::CountLeadingZeros64(value);
+  if (width == 32) return Utils::CountLeadingZeros32(value);
+  UNREACHABLE();
+  return 0;
 }
 
 static int CountOneBits(uint64_t value, int width) {
@@ -240,7 +235,9 @@
 bool Operand::IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op) {
   ASSERT(imm_op != NULL);
   ASSERT((width == kWRegSizeInBits) || (width == kXRegSizeInBits));
-  ASSERT((width == kXRegSizeInBits) || (value <= 0xffffffffUL));
+  if (width == kWRegSizeInBits) {
+    value &= 0xffffffffUL;
+  }
   uint8_t n = 0;
   uint8_t imm_s = 0;
   uint8_t imm_r = 0;
@@ -696,31 +693,19 @@
                                      int64_t imm,
                                      OperandSize sz) {
   ASSERT(sz == kEightBytes || sz == kFourBytes);
+  int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
   Operand op;
-  if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) {
+  if (Operand::CanHold(imm, width, &op) == Operand::Immediate) {
     // Handles imm == kMinInt64.
-    if (sz == kEightBytes) {
-      adds(dest, rn, op);
-    } else {
-      addsw(dest, rn, op);
-    }
-  } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) ==
-             Operand::Immediate) {
+    adds(dest, rn, op, sz);
+  } else if (Operand::CanHold(-imm, width, &op) == Operand::Immediate) {
     ASSERT(imm != kMinInt64);  // Would cause erroneous overflow detection.
-    if (sz == kEightBytes) {
-      subs(dest, rn, op);
-    } else {
-      subsw(dest, rn, op);
-    }
+    subs(dest, rn, op, sz);
   } else {
     // TODO(zra): Try adding top 12 bits, then bottom 12 bits.
     ASSERT(rn != TMP2);
     LoadImmediate(TMP2, imm);
-    if (sz == kEightBytes) {
-      adds(dest, rn, Operand(TMP2));
-    } else {
-      addsw(dest, rn, Operand(TMP2));
-    }
+    adds(dest, rn, Operand(TMP2), sz);
   }
 }
 
@@ -728,86 +713,93 @@
                                      Register rn,
                                      int64_t imm,
                                      OperandSize sz) {
-  Operand op;
   ASSERT(sz == kEightBytes || sz == kFourBytes);
-  if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) {
+  int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
+  Operand op;
+  if (Operand::CanHold(imm, width, &op) == Operand::Immediate) {
     // Handles imm == kMinInt64.
-    if (sz == kEightBytes) {
-      subs(dest, rn, op);
-    } else {
-      subsw(dest, rn, op);
-    }
-  } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) ==
-             Operand::Immediate) {
+    subs(dest, rn, op, sz);
+  } else if (Operand::CanHold(-imm, width, &op) == Operand::Immediate) {
     ASSERT(imm != kMinInt64);  // Would cause erroneous overflow detection.
-    if (sz == kEightBytes) {
-      adds(dest, rn, op);
-    } else {
-      addsw(dest, rn, op);
-    }
+    adds(dest, rn, op, sz);
   } else {
     // TODO(zra): Try subtracting top 12 bits, then bottom 12 bits.
     ASSERT(rn != TMP2);
     LoadImmediate(TMP2, imm);
-    if (sz == kEightBytes) {
-      subs(dest, rn, Operand(TMP2));
-    } else {
-      subsw(dest, rn, Operand(TMP2));
-    }
+    subs(dest, rn, Operand(TMP2), sz);
   }
 }
 
-void Assembler::AndImmediate(Register rd, Register rn, int64_t imm) {
+void Assembler::AndImmediate(Register rd,
+                             Register rn,
+                             int64_t imm,
+                             OperandSize sz) {
+  ASSERT(sz == kEightBytes || sz == kFourBytes);
+  int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
   Operand imm_op;
-  if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
-    andi(rd, rn, Immediate(imm));
+  if (Operand::IsImmLogical(imm, width, &imm_op)) {
+    andi(rd, rn, Immediate(imm), sz);
   } else {
     LoadImmediate(TMP, imm);
-    and_(rd, rn, Operand(TMP));
+    and_(rd, rn, Operand(TMP), sz);
   }
 }
 
-void Assembler::OrImmediate(Register rd, Register rn, int64_t imm) {
+void Assembler::OrImmediate(Register rd,
+                            Register rn,
+                            int64_t imm,
+                            OperandSize sz) {
+  ASSERT(sz == kEightBytes || sz == kFourBytes);
+  int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
   Operand imm_op;
-  if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
-    orri(rd, rn, Immediate(imm));
+  if (Operand::IsImmLogical(imm, width, &imm_op)) {
+    orri(rd, rn, Immediate(imm), sz);
   } else {
     LoadImmediate(TMP, imm);
-    orr(rd, rn, Operand(TMP));
+    orr(rd, rn, Operand(TMP), sz);
   }
 }
 
-void Assembler::XorImmediate(Register rd, Register rn, int64_t imm) {
+void Assembler::XorImmediate(Register rd,
+                             Register rn,
+                             int64_t imm,
+                             OperandSize sz) {
+  ASSERT(sz == kEightBytes || sz == kFourBytes);
+  int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
   Operand imm_op;
-  if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
-    eori(rd, rn, Immediate(imm));
+  if (Operand::IsImmLogical(imm, width, &imm_op)) {
+    eori(rd, rn, Immediate(imm), sz);
   } else {
     LoadImmediate(TMP, imm);
-    eor(rd, rn, Operand(TMP));
+    eor(rd, rn, Operand(TMP), sz);
   }
 }
 
-void Assembler::TestImmediate(Register rn, int64_t imm) {
+void Assembler::TestImmediate(Register rn, int64_t imm, OperandSize sz) {
+  ASSERT(sz == kEightBytes || sz == kFourBytes);
+  int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
   Operand imm_op;
-  if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
-    tsti(rn, Immediate(imm));
+  if (Operand::IsImmLogical(imm, width, &imm_op)) {
+    tsti(rn, Immediate(imm), sz);
   } else {
     LoadImmediate(TMP, imm);
     tst(rn, Operand(TMP));
   }
 }
 
-void Assembler::CompareImmediate(Register rn, int64_t imm) {
+void Assembler::CompareImmediate(Register rn, int64_t imm, OperandSize sz) {
+  ASSERT(sz == kEightBytes || sz == kFourBytes);
+  int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
   Operand op;
-  if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) {
-    cmp(rn, op);
-  } else if (Operand::CanHold(-static_cast<uint64_t>(imm), kXRegSizeInBits,
-                              &op) == Operand::Immediate) {
-    cmn(rn, op);
+  if (Operand::CanHold(imm, width, &op) == Operand::Immediate) {
+    cmp(rn, op, sz);
+  } else if (Operand::CanHold(-static_cast<uint64_t>(imm), width, &op) ==
+             Operand::Immediate) {
+    cmn(rn, op, sz);
   } else {
     ASSERT(rn != TMP2);
     LoadImmediate(TMP2, imm);
-    cmp(rn, Operand(TMP2));
+    cmp(rn, Operand(TMP2), sz);
   }
 }
 
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 79eff28..14ac5aa 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -628,29 +628,25 @@
   // Addition and subtraction.
   // For add and sub, to use CSP for rn, o must be of type Operand::Extend.
   // For an unmodified rm in this case, use Operand(rm, UXTX, 0);
-  void add(Register rd, Register rn, Operand o) {
-    AddSubHelper(kEightBytes, false, false, rd, rn, o);
+  void add(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    AddSubHelper(sz, false, false, rd, rn, o);
   }
-  void adds(Register rd, Register rn, Operand o) {
-    AddSubHelper(kEightBytes, true, false, rd, rn, o);
+  void adds(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    AddSubHelper(sz, true, false, rd, rn, o);
   }
-  void addw(Register rd, Register rn, Operand o) {
-    AddSubHelper(kFourBytes, false, false, rd, rn, o);
+  void sub(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    AddSubHelper(sz, false, true, rd, rn, o);
   }
+  void subs(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    AddSubHelper(sz, true, true, rd, rn, o);
+  }
+  void addw(Register rd, Register rn, Operand o) { add(rd, rn, o, kFourBytes); }
   void addsw(Register rd, Register rn, Operand o) {
-    AddSubHelper(kFourBytes, true, false, rd, rn, o);
+    adds(rd, rn, o, kFourBytes);
   }
-  void sub(Register rd, Register rn, Operand o) {
-    AddSubHelper(kEightBytes, false, true, rd, rn, o);
-  }
-  void subs(Register rd, Register rn, Operand o) {
-    AddSubHelper(kEightBytes, true, true, rd, rn, o);
-  }
-  void subw(Register rd, Register rn, Operand o) {
-    AddSubHelper(kFourBytes, false, true, rd, rn, o);
-  }
+  void subw(Register rd, Register rn, Operand o) { sub(rd, rn, o, kFourBytes); }
   void subsw(Register rd, Register rn, Operand o) {
-    AddSubHelper(kFourBytes, true, true, rd, rn, o);
+    subs(rd, rn, o, kFourBytes);
   }
 
   // Addition and subtraction with carry.
@@ -810,72 +806,82 @@
   }
 
   // Logical immediate operations.
-  void andi(Register rd, Register rn, const Immediate& imm) {
+  void andi(Register rd,
+            Register rn,
+            const Immediate& imm,
+            OperandSize sz = kEightBytes) {
+    ASSERT(sz == kEightBytes || sz == kFourBytes);
+    int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
     Operand imm_op;
-    const bool immok =
-        Operand::IsImmLogical(imm.value(), kXRegSizeInBits, &imm_op);
+    const bool immok = Operand::IsImmLogical(imm.value(), width, &imm_op);
     ASSERT(immok);
-    EmitLogicalImmOp(ANDI, rd, rn, imm_op, kEightBytes);
+    EmitLogicalImmOp(ANDI, rd, rn, imm_op, sz);
   }
-  void orri(Register rd, Register rn, const Immediate& imm) {
+  void orri(Register rd,
+            Register rn,
+            const Immediate& imm,
+            OperandSize sz = kEightBytes) {
+    ASSERT(sz == kEightBytes || sz == kFourBytes);
+    int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
     Operand imm_op;
-    const bool immok =
-        Operand::IsImmLogical(imm.value(), kXRegSizeInBits, &imm_op);
+    const bool immok = Operand::IsImmLogical(imm.value(), width, &imm_op);
     ASSERT(immok);
-    EmitLogicalImmOp(ORRI, rd, rn, imm_op, kEightBytes);
+    EmitLogicalImmOp(ORRI, rd, rn, imm_op, sz);
   }
-  void eori(Register rd, Register rn, const Immediate& imm) {
+  void eori(Register rd,
+            Register rn,
+            const Immediate& imm,
+            OperandSize sz = kEightBytes) {
+    ASSERT(sz == kEightBytes || sz == kFourBytes);
+    int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
     Operand imm_op;
-    const bool immok =
-        Operand::IsImmLogical(imm.value(), kXRegSizeInBits, &imm_op);
+    const bool immok = Operand::IsImmLogical(imm.value(), width, &imm_op);
     ASSERT(immok);
-    EmitLogicalImmOp(EORI, rd, rn, imm_op, kEightBytes);
+    EmitLogicalImmOp(EORI, rd, rn, imm_op, sz);
   }
-  void andis(Register rd, Register rn, const Immediate& imm) {
+  void andis(Register rd,
+             Register rn,
+             const Immediate& imm,
+             OperandSize sz = kEightBytes) {
+    ASSERT(sz == kEightBytes || sz == kFourBytes);
+    int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
     Operand imm_op;
-    const bool immok =
-        Operand::IsImmLogical(imm.value(), kXRegSizeInBits, &imm_op);
+    const bool immok = Operand::IsImmLogical(imm.value(), width, &imm_op);
     ASSERT(immok);
-    EmitLogicalImmOp(ANDIS, rd, rn, imm_op, kEightBytes);
+    EmitLogicalImmOp(ANDIS, rd, rn, imm_op, sz);
   }
 
   // Logical (shifted) register operations.
-  void and_(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(AND, rd, rn, o, kEightBytes);
+  void and_(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    EmitLogicalShiftOp(AND, rd, rn, o, sz);
+  }
+  void bic(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    EmitLogicalShiftOp(BIC, rd, rn, o, sz);
+  }
+  void orr(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    EmitLogicalShiftOp(ORR, rd, rn, o, sz);
+  }
+  void orn(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    EmitLogicalShiftOp(ORN, rd, rn, o, sz);
+  }
+  void eor(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    EmitLogicalShiftOp(EOR, rd, rn, o, sz);
+  }
+  void eon(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    EmitLogicalShiftOp(EON, rd, rn, o, sz);
+  }
+  void ands(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    EmitLogicalShiftOp(ANDS, rd, rn, o, sz);
+  }
+  void bics(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+    EmitLogicalShiftOp(BICS, rd, rn, o, sz);
   }
   void andw_(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(AND, rd, rn, o, kFourBytes);
+    and_(rd, rn, o, kFourBytes);
   }
-  void bic(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(BIC, rd, rn, o, kEightBytes);
-  }
-  void orr(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(ORR, rd, rn, o, kEightBytes);
-  }
-  void orrw(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(ORR, rd, rn, o, kFourBytes);
-  }
-  void orn(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(ORN, rd, rn, o, kEightBytes);
-  }
-  void ornw(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(ORN, rd, rn, o, kFourBytes);
-  }
-  void eor(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(EOR, rd, rn, o, kEightBytes);
-  }
-  void eorw(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(EOR, rd, rn, o, kFourBytes);
-  }
-  void eon(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(EON, rd, rn, o, kEightBytes);
-  }
-  void ands(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(ANDS, rd, rn, o, kEightBytes);
-  }
-  void bics(Register rd, Register rn, Operand o) {
-    EmitLogicalShiftOp(BICS, rd, rn, o, kEightBytes);
-  }
+  void orrw(Register rd, Register rn, Operand o) { orr(rd, rn, o, kFourBytes); }
+  void ornw(Register rd, Register rn, Operand o) { orn(rd, rn, o, kFourBytes); }
+  void eorw(Register rd, Register rn, Operand o) { eor(rd, rn, o, kFourBytes); }
 
   // Count leading zero bits.
   void clz(Register rd, Register rn) {
@@ -1090,10 +1096,14 @@
   // rn cmp o.
   // For add and sub, to use CSP for rn, o must be of type Operand::Extend.
   // For an unmodified rm in this case, use Operand(rm, UXTX, 0);
-  void cmp(Register rn, Operand o) { subs(ZR, rn, o); }
-  void cmpw(Register rn, Operand o) { subsw(ZR, rn, o); }
+  void cmp(Register rn, Operand o, OperandSize sz = kEightBytes) {
+    subs(ZR, rn, o, sz);
+  }
+  void cmpw(Register rn, Operand o) { cmp(rn, o, kFourBytes); }
   // rn cmp -o.
-  void cmn(Register rn, Operand o) { adds(ZR, rn, o); }
+  void cmn(Register rn, Operand o, OperandSize sz = kEightBytes) {
+    adds(ZR, rn, o, sz);
+  }
 
   void CompareRegisters(Register rn, Register rm) {
     if (rn == CSP) {
@@ -1490,8 +1500,12 @@
     // The caller of PopAndUntagPP() must explicitly allow use of popped PP.
     set_constant_pool_allowed(false);
   }
-  void tst(Register rn, Operand o) { ands(ZR, rn, o); }
-  void tsti(Register rn, const Immediate& imm) { andis(ZR, rn, imm); }
+  void tst(Register rn, Operand o, OperandSize sz = kEightBytes) {
+    ands(ZR, rn, o, sz);
+  }
+  void tsti(Register rn, const Immediate& imm, OperandSize sz = kEightBytes) {
+    andis(ZR, rn, imm, sz);
+  }
 
   void LslImmediate(Register rd,
                     Register rn,
@@ -1612,11 +1626,20 @@
                             Register rn,
                             int64_t imm,
                             OperandSize sz = kEightBytes);
-  void AndImmediate(Register rd, Register rn, int64_t imm);
-  void OrImmediate(Register rd, Register rn, int64_t imm);
-  void XorImmediate(Register rd, Register rn, int64_t imm);
-  void TestImmediate(Register rn, int64_t imm);
-  void CompareImmediate(Register rn, int64_t imm);
+  void AndImmediate(Register rd,
+                    Register rn,
+                    int64_t imm,
+                    OperandSize sz = kEightBytes);
+  void OrImmediate(Register rd,
+                   Register rn,
+                   int64_t imm,
+                   OperandSize sz = kEightBytes);
+  void XorImmediate(Register rd,
+                    Register rn,
+                    int64_t imm,
+                    OperandSize sz = kEightBytes);
+  void TestImmediate(Register rn, int64_t imm, OperandSize sz = kEightBytes);
+  void CompareImmediate(Register rn, int64_t imm, OperandSize sz = kEightBytes);
 
   void LoadFromOffset(Register dest,
                       const Address& address,
diff --git a/runtime/vm/compiler/assembler/assembler_arm64_test.cc b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
index 62129c2..4451d4f 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
@@ -4773,6 +4773,91 @@
             EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
 }
 
+ASSEMBLER_TEST_GENERATE(AndImmediate32Negative, assembler) {
+  __ AndImmediate(R0, R0, -512, kFourBytes);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(AndImmediate32Negative, test) {
+  typedef intptr_t (*IntPtrReturn)(intptr_t) DART_UNUSED;
+  EXPECT_EQ(0xfffffe00,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -42));
+  EXPECT_EQ(0, EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 0));
+  EXPECT_EQ(0,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 42));
+}
+
+ASSEMBLER_TEST_GENERATE(OrImmediate32Negative, assembler) {
+  __ OrImmediate(R0, R0, -512, kFourBytes);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(OrImmediate32Negative, test) {
+  typedef intptr_t (*IntPtrReturn)(intptr_t) DART_UNUSED;
+  EXPECT_EQ(0xffffffd6,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -42));
+  EXPECT_EQ(0xfffffe00,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 0));
+  EXPECT_EQ(0xfffffe2a,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 42));
+}
+
+ASSEMBLER_TEST_GENERATE(XorImmediate32Negative, assembler) {
+  __ XorImmediate(R0, R0, -512, kFourBytes);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(XorImmediate32Negative, test) {
+  typedef intptr_t (*IntPtrReturn)(intptr_t) DART_UNUSED;
+  EXPECT_EQ(0x1d6,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -42));
+  EXPECT_EQ(0xfffffe00,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 0));
+  EXPECT_EQ(0xfffffe2a,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 42));
+}
+
+ASSEMBLER_TEST_GENERATE(TestImmediate32Negative, assembler) {
+  Label on_zero;
+  __ TestImmediate(R0, -512, kFourBytes);
+  __ b(&on_zero, EQ);
+  __ LoadImmediate(R0, 1);
+  __ ret();
+  __ Bind(&on_zero);
+  __ LoadImmediate(R0, 0);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(TestImmediate32Negative, test) {
+  typedef intptr_t (*IntPtrReturn)(intptr_t) DART_UNUSED;
+  EXPECT_EQ(1,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -42));
+  EXPECT_EQ(0, EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 0));
+  EXPECT_EQ(0,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 42));
+}
+
+ASSEMBLER_TEST_GENERATE(CompareImmediate32Negative, assembler) {
+  Label on_zero;
+  __ CompareImmediate(R0, -512, kFourBytes);
+  __ b(&on_zero, LT);
+  __ LoadImmediate(R0, 0);
+  __ ret();
+  __ Bind(&on_zero);
+  __ LoadImmediate(R0, 1);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(CompareImmediate32Negative, test) {
+  typedef intptr_t (*IntPtrReturn)(intptr_t) DART_UNUSED;
+  EXPECT_EQ(1,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -513));
+  EXPECT_EQ(0,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -512));
+  EXPECT_EQ(0,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -511));
+}
+
 }  // namespace compiler
 }  // namespace dart
 
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 363fd1e..db937ad 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -648,14 +648,8 @@
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   auto isolate_group = thread->isolate_group();
-  Class& error_class =
+  const auto& error_class =
       Class::Handle(zone, isolate_group->object_store()->error_class());
-  if (error_class.IsNull()) {
-    const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
-    error_class = core_lib.LookupClass(Symbols::Error());
-    ASSERT(!error_class.IsNull());
-    isolate_group->object_store()->set_error_class(error_class);
-  }
   // If instance class extends 'class Error' return '_stackTrace' field.
   Class& test_class = Class::Handle(zone, instance.clazz());
   AbstractType& type = AbstractType::Handle(zone, AbstractType::null());
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 208f123..dbe84b2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -722,7 +722,7 @@
     cls.set_is_type_finalized();
     cls.set_type_arguments_field_offset_in_words(Class::kNoTypeArguments,
                                                  RTN::Class::kNoTypeArguments);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_num_native_fields(0);
     cls.InitEmptyFields();
     isolate_group->class_table()->Register(cls);
@@ -730,12 +730,12 @@
 
   // Allocate and initialize the null class.
   cls = Class::New<Instance, RTN::Instance>(kNullCid, isolate_group);
-  cls.set_num_type_arguments(0);
+  cls.set_num_type_arguments_unsafe(0);
   isolate_group->object_store()->set_null_class(cls);
 
   // Allocate and initialize Never class.
   cls = Class::New<Instance, RTN::Instance>(kNeverCid, isolate_group);
-  cls.set_num_type_arguments(0);
+  cls.set_num_type_arguments_unsafe(0);
   cls.set_is_allocate_finalized();
   cls.set_is_declaration_loaded();
   cls.set_is_type_finalized();
@@ -745,7 +745,7 @@
   cls = Class::New<FreeListElement::FakeInstance,
                    RTN::FreeListElement::FakeInstance>(kFreeListElement,
                                                        isolate_group);
-  cls.set_num_type_arguments(0);
+  cls.set_num_type_arguments_unsafe(0);
   cls.set_is_allocate_finalized();
   cls.set_is_declaration_loaded();
   cls.set_is_type_finalized();
@@ -754,7 +754,7 @@
   cls = Class::New<ForwardingCorpse::FakeInstance,
                    RTN::ForwardingCorpse::FakeInstance>(kForwardingCorpse,
                                                         isolate_group);
-  cls.set_num_type_arguments(0);
+  cls.set_num_type_arguments_unsafe(0);
   cls.set_is_allocate_finalized();
   cls.set_is_declaration_loaded();
   cls.set_is_type_finalized();
@@ -889,19 +889,19 @@
   isolate_group->object_store()->set_array_class(cls);
   cls.set_type_arguments_field_offset(Array::type_arguments_offset(),
                                       RTN::Array::type_arguments_offset());
-  cls.set_num_type_arguments(1);
+  cls.set_num_type_arguments_unsafe(1);
   cls = Class::New<Array, RTN::Array>(kImmutableArrayCid, isolate_group);
   isolate_group->object_store()->set_immutable_array_class(cls);
   cls.set_type_arguments_field_offset(Array::type_arguments_offset(),
                                       RTN::Array::type_arguments_offset());
-  cls.set_num_type_arguments(1);
+  cls.set_num_type_arguments_unsafe(1);
   cls =
       Class::New<GrowableObjectArray, RTN::GrowableObjectArray>(isolate_group);
   isolate_group->object_store()->set_growable_object_array_class(cls);
   cls.set_type_arguments_field_offset(
       GrowableObjectArray::type_arguments_offset(),
       RTN::GrowableObjectArray::type_arguments_offset());
-  cls.set_num_type_arguments(1);
+  cls.set_num_type_arguments_unsafe(1);
   cls = Class::NewStringClass(kOneByteStringCid, isolate_group);
   isolate_group->object_store()->set_one_byte_string_class(cls);
   cls = Class::NewStringClass(kTwoByteStringCid, isolate_group);
@@ -1045,14 +1045,14 @@
 
   cls = Class::New<Instance, RTN::Instance>(kDynamicCid, isolate_group);
   cls.set_is_abstract();
-  cls.set_num_type_arguments(0);
+  cls.set_num_type_arguments_unsafe(0);
   cls.set_is_allocate_finalized();
   cls.set_is_declaration_loaded();
   cls.set_is_type_finalized();
   dynamic_class_ = cls.ptr();
 
   cls = Class::New<Instance, RTN::Instance>(kVoidCid, isolate_group);
-  cls.set_num_type_arguments(0);
+  cls.set_num_type_arguments_unsafe(0);
   cls.set_is_allocate_finalized();
   cls.set_is_declaration_loaded();
   cls.set_is_type_finalized();
@@ -1599,7 +1599,7 @@
     // respective Raw* classes.
     cls.set_type_arguments_field_offset(Array::type_arguments_offset(),
                                         RTN::Array::type_arguments_offset());
-    cls.set_num_type_arguments(1);
+    cls.set_num_type_arguments_unsafe(1);
 
     // Set up the growable object array class (Has to be done after the array
     // class is setup as one of its field is an array object).
@@ -1609,7 +1609,7 @@
     cls.set_type_arguments_field_offset(
         GrowableObjectArray::type_arguments_offset(),
         RTN::GrowableObjectArray::type_arguments_offset());
-    cls.set_num_type_arguments(1);
+    cls.set_num_type_arguments_unsafe(1);
 
     // Initialize hash set for canonical types.
     const intptr_t kInitialCanonicalTypeSize = 16;
@@ -1704,7 +1704,7 @@
     object_store->set_immutable_array_class(cls);
     cls.set_type_arguments_field_offset(Array::type_arguments_offset(),
                                         RTN::Array::type_arguments_offset());
-    cls.set_num_type_arguments(1);
+    cls.set_num_type_arguments_unsafe(1);
     ASSERT(object_store->immutable_array_class() !=
            object_store->array_class());
     cls.set_is_prefinalized();
@@ -1778,7 +1778,7 @@
     cls = Class::New<Instance, RTN::Instance>(kInstanceCid, isolate_group);
     object_store->set_object_class(cls);
     cls.set_name(Symbols::Object());
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     cls.set_is_const();
     core_lib.AddClass(cls);
@@ -1803,13 +1803,13 @@
 
     cls = Class::New<Instance, RTN::Instance>(kNullCid, isolate_group);
     object_store->set_null_class(cls);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     RegisterClass(cls, Symbols::Null(), core_lib);
     pending_classes.Add(cls);
 
     cls = Class::New<Instance, RTN::Instance>(kNeverCid, isolate_group);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_allocate_finalized();
     cls.set_is_declaration_loaded();
     cls.set_is_type_finalized();
@@ -1896,7 +1896,7 @@
     cls.set_type_arguments_field_offset(
         LinkedHashMap::type_arguments_offset(),
         RTN::LinkedHashMap::type_arguments_offset());
-    cls.set_num_type_arguments(2);
+    cls.set_num_type_arguments_unsafe(2);
     RegisterPrivateClass(cls, Symbols::_LinkedHashMap(), lib);
     pending_classes.Add(cls);
 
@@ -1914,7 +1914,7 @@
     cls = Class::New<FutureOr, RTN::FutureOr>(isolate_group);
     cls.set_type_arguments_field_offset(FutureOr::type_arguments_offset(),
                                         RTN::FutureOr::type_arguments_offset());
-    cls.set_num_type_arguments(1);
+    cls.set_num_type_arguments_unsafe(1);
     RegisterClass(cls, Symbols::FutureOr(), lib);
     pending_classes.Add(cls);
 
@@ -1993,7 +1993,7 @@
                                               /*register_class=*/true,
                                               /*is_abstract=*/true);
     RegisterClass(cls, Symbols::Float32x4(), lib);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     type = Type::NewNonParameterizedType(cls);
     object_store->set_float32x4_type(type);
@@ -2007,7 +2007,7 @@
                                               /*register_class=*/true,
                                               /*is_abstract=*/true);
     RegisterClass(cls, Symbols::Int32x4(), lib);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     type = Type::NewNonParameterizedType(cls);
     object_store->set_int32x4_type(type);
@@ -2021,7 +2021,7 @@
                                               /*register_class=*/true,
                                               /*is_abstract=*/true);
     RegisterClass(cls, Symbols::Float64x2(), lib);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     type = Type::NewNonParameterizedType(cls);
     object_store->set_float64x2_type(type);
@@ -2036,7 +2036,7 @@
     cls = Class::New<Instance, RTN::Instance>(kIllegalCid, isolate_group,
                                               /*register_class=*/true,
                                               /*is_abstract=*/true);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     RegisterClass(cls, Symbols::Type(), core_lib);
     pending_classes.Add(cls);
@@ -2047,7 +2047,7 @@
     cls = Class::New<Instance, RTN::Instance>(kIllegalCid, isolate_group,
                                               /*register_class=*/true,
                                               /*is_abstract=*/true);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     RegisterClass(cls, Symbols::Function(), core_lib);
     pending_classes.Add(cls);
@@ -2072,7 +2072,7 @@
                                               /*register_class=*/true,
                                               /*is_abstract=*/true);
     RegisterClass(cls, Symbols::Int(), core_lib);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     pending_classes.Add(cls);
     type = Type::NewNonParameterizedType(cls);
@@ -2088,7 +2088,7 @@
                                               /*register_class=*/true,
                                               /*is_abstract=*/true);
     RegisterClass(cls, Symbols::Double(), core_lib);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     pending_classes.Add(cls);
     type = Type::NewNonParameterizedType(cls);
@@ -2105,7 +2105,7 @@
                                               /*register_class=*/true,
                                               /*is_abstract=*/true);
     RegisterClass(cls, name, core_lib);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     pending_classes.Add(cls);
     type = Type::NewNonParameterizedType(cls);
@@ -2262,7 +2262,7 @@
     object_store->set_bootstrap_library(ObjectStore::kFfi, lib);
 
     cls = Class::New<Instance, RTN::Instance>(kFfiNativeTypeCid, isolate_group);
-    cls.set_num_type_arguments(0);
+    cls.set_num_type_arguments_unsafe(0);
     cls.set_is_prefinalized();
     pending_classes.Add(cls);
     object_store->set_ffi_native_type_class(cls);
@@ -2270,7 +2270,7 @@
 
 #define REGISTER_FFI_TYPE_MARKER(clazz)                                        \
   cls = Class::New<Instance, RTN::Instance>(kFfi##clazz##Cid, isolate_group);  \
-  cls.set_num_type_arguments(0);                                               \
+  cls.set_num_type_arguments_unsafe(0);                                        \
   cls.set_is_prefinalized();                                                   \
   pending_classes.Add(cls);                                                    \
   RegisterClass(cls, Symbols::Ffi##clazz(), lib);
@@ -2281,7 +2281,7 @@
                                               isolate_group);
     cls.set_type_arguments_field_offset(Pointer::type_arguments_offset(),
                                         RTN::Pointer::type_arguments_offset());
-    cls.set_num_type_arguments(1);
+    cls.set_num_type_arguments_unsafe(1);
     cls.set_is_prefinalized();
     pending_classes.Add(cls);
     RegisterClass(cls, Symbols::FfiNativeFunction(), lib);
@@ -2811,7 +2811,7 @@
                                target_next_field_offset);
   COMPILE_ASSERT((FakeObject::kClassId != kInstanceCid));
   result.set_id(FakeObject::kClassId);
-  result.set_num_type_arguments(0);
+  result.set_num_type_arguments_unsafe(0);
   result.set_num_native_fields(0);
   result.set_state_bits(0);
   if ((FakeObject::kClassId < kInstanceCid) ||
@@ -2847,6 +2847,15 @@
   if (!Utils::IsInt(16, value)) {
     ReportTooManyTypeArguments(*this);
   }
+  // We allow concurrent calculation of the number of type arguments. If two
+  // threads perform this operation it doesn't matter which one wins.
+  DEBUG_ONLY(intptr_t old_value = num_type_arguments());
+  DEBUG_ASSERT(old_value == kUnknownNumTypeArguments || old_value == value);
+  StoreNonPointer<int16_t, int16_t, std::memory_order_relaxed>(
+      &untag()->num_type_arguments_, value);
+}
+
+void Class::set_num_type_arguments_unsafe(intptr_t value) const {
   StoreNonPointer(&untag()->num_type_arguments_, value);
 }
 
@@ -4509,7 +4518,7 @@
   result.set_next_field_offset(host_next_field_offset,
                                target_next_field_offset);
   result.set_id(index);
-  result.set_num_type_arguments(kUnknownNumTypeArguments);
+  result.set_num_type_arguments_unsafe(kUnknownNumTypeArguments);
   result.set_num_native_fields(0);
   result.set_state_bits(0);
   NOT_IN_PRECOMPILED(result.set_kernel_offset(0));
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 7704001..01cfb33 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1677,7 +1677,10 @@
   // Initial value for the cached number of type arguments.
   static const intptr_t kUnknownNumTypeArguments = -1;
 
-  int16_t num_type_arguments() const { return untag()->num_type_arguments_; }
+  int16_t num_type_arguments() const {
+    return LoadNonPointer<int16_t, std::memory_order_relaxed>(
+        &untag()->num_type_arguments_);
+  }
 
   uint32_t state_bits() const {
     // Ensure any following load instructions do not get performed before this
@@ -1688,6 +1691,7 @@
 
  public:
   void set_num_type_arguments(intptr_t value) const;
+  void set_num_type_arguments_unsafe(intptr_t value) const;
 
   bool has_pragma() const { return HasPragmaBit::decode(state_bits()); }
   void set_has_pragma(bool has_pragma) const;
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 57343da..1f75699 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -281,6 +281,10 @@
       cls.LookupFactoryAllowPrivate(Symbols::_GrowableListFactory());
   ASSERT(growable_list_factory_ != Function::null());
 
+  cls = core_lib.LookupClassAllowPrivate(Symbols::Error());
+  ASSERT(!cls.IsNull());
+  set_error_class(cls);
+
   // Cache the core private functions used for fast instance of checks.
   simple_instance_of_function_ =
       PrivateObjectLookup(Symbols::_simpleInstanceOf());
diff --git a/runtime/vm/virtual_memory_compressed.h b/runtime/vm/virtual_memory_compressed.h
index 9b55243..95f4d52 100644
--- a/runtime/vm/virtual_memory_compressed.h
+++ b/runtime/vm/virtual_memory_compressed.h
@@ -5,18 +5,13 @@
 #ifndef RUNTIME_VM_VIRTUAL_MEMORY_COMPRESSED_H_
 #define RUNTIME_VM_VIRTUAL_MEMORY_COMPRESSED_H_
 
-#if defined(DART_COMPRESSED_POINTERS) && !defined(HOST_OS_FUCHSIA)
-#define DART_COMPRESSED_HEAP
-#endif  // defined(DART_COMPRESSED_POINTERS) && !defined(HOST_OS_FUCHSIA)
-
-#if defined(DART_COMPRESSED_HEAP)
-
 #include "vm/globals.h"
 #include "vm/heap/pages.h"
 #include "vm/memory_region.h"
 
 namespace dart {
 
+#if defined(DART_COMPRESSED_POINTERS)
 static constexpr intptr_t kCompressedHeapSize = 2 * GB;
 static constexpr intptr_t kCompressedHeapAlignment = 4 * GB;
 static constexpr intptr_t kCompressedHeapPageSize = kOldPageSize;
@@ -25,6 +20,13 @@
 static constexpr intptr_t kCompressedHeapBitmapSize =
     kCompressedHeapNumPages / 8;
 
+#if !defined(HOST_OS_FUCHSIA)
+#define DART_COMPRESSED_HEAP
+#endif  // !defined(HOST_OS_FUCHSIA)
+#endif  // defined(DART_COMPRESSED_POINTERS)
+
+#if defined(DART_COMPRESSED_HEAP)
+
 // Utilities for allocating memory within a contiguous region of memory, for use
 // with compressed pointers.
 class VirtualMemoryCompressedHeap : public AllStatic {
@@ -61,8 +63,8 @@
   static Mutex* mutex_;
 };
 
-}  // namespace dart
-
 #endif  // defined(DART_COMPRESSED_HEAP)
 
+}  // namespace dart
+
 #endif  // RUNTIME_VM_VIRTUAL_MEMORY_COMPRESSED_H_
diff --git a/runtime/vm/virtual_memory_fuchsia.cc b/runtime/vm/virtual_memory_fuchsia.cc
index a5a6d14..731b86d 100644
--- a/runtime/vm/virtual_memory_fuchsia.cc
+++ b/runtime/vm/virtual_memory_fuchsia.cc
@@ -21,6 +21,7 @@
 #include "vm/memory_region.h"
 #include "vm/os.h"
 #include "vm/os_thread.h"
+#include "vm/virtual_memory_compressed.h"
 
 // #define VIRTUAL_MEMORY_LOGGING 1
 #if defined(VIRTUAL_MEMORY_LOGGING)
@@ -40,6 +41,11 @@
 
 uword VirtualMemory::page_size_ = 0;
 
+#if defined(DART_COMPRESSED_POINTERS)
+static zx_handle_t compressed_heap_vmar_ = ZX_HANDLE_INVALID;
+static uword compressed_heap_base_ = 0;
+#endif  // defined(DART_COMPRESSED_POINTERS)
+
 intptr_t VirtualMemory::CalculatePageSize() {
   const intptr_t page_size = getpagesize();
   ASSERT(page_size != 0);
@@ -48,10 +54,45 @@
 }
 
 void VirtualMemory::Init() {
+#if defined(DART_COMPRESSED_POINTERS)
+  if (compressed_heap_vmar_ == ZX_HANDLE_INVALID) {
+    const zx_vm_option_t align_flag =
+        Utils::ShiftForPowerOfTwo(kCompressedHeapAlignment) << ZX_VM_ALIGN_BASE;
+    const zx_vm_option_t options = ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE |
+                                   ZX_VM_CAN_MAP_SPECIFIC | align_flag;
+    zx_vaddr_t region;
+    zx_status_t status =
+        zx_vmar_allocate(zx_vmar_root_self(), options, 0, kCompressedHeapSize,
+                         &compressed_heap_vmar_, &region);
+    if (status != ZX_OK) {
+      LOG_ERR("zx_vmar_allocate(0x%lx) failed: %s\n", kCompressedHeapSize,
+              zx_status_get_string(status));
+    } else {
+      compressed_heap_base_ = reinterpret_cast<uword>(region);
+      ASSERT(Utils::IsAligned(compressed_heap_base_, kCompressedHeapAlignment));
+    }
+  }
+#endif  // defined(DART_COMPRESSED_POINTERS)
+
   page_size_ = CalculatePageSize();
 }
 
-void VirtualMemory::Cleanup() {}
+void VirtualMemory::Cleanup() {
+#if defined(DART_COMPRESSED_POINTERS)
+  zx_vmar_destroy(compressed_heap_vmar_);
+  compressed_heap_vmar_ = ZX_HANDLE_INVALID;
+  compressed_heap_base_ = 0;
+#endif  // defined(DART_COMPRESSED_POINTERS)
+}
+
+static zx_handle_t getVmarForAddress(uword address) {
+#if defined(DART_COMPRESSED_POINTERS)
+  if (address - compressed_heap_base_ < kCompressedHeapSize) {
+    return compressed_heap_vmar_;
+  }
+#endif  // defined(DART_COMPRESSED_POINTERS)
+  return zx_vmar_root_self();
+}
 
 static void Unmap(zx_handle_t vmar, uword start, uword end) {
   ASSERT(start <= end);
@@ -94,7 +135,12 @@
                                     << ZX_VM_ALIGN_BASE;
   ASSERT((ZX_VM_ALIGN_1KB <= align_flag) && (align_flag <= ZX_VM_ALIGN_4GB));
 
+#if defined(DART_COMPRESSED_POINTERS)
+  zx_handle_t vmar =
+      is_executable ? zx_vmar_root_self() : compressed_heap_vmar_;
+#else
   zx_handle_t vmar = zx_vmar_root_self();
+#endif  // defined(DART_COMPRESSED_POINTERS)
   zx_handle_t vmo = ZX_HANDLE_INVALID;
   zx_status_t status = zx_vmo_create(size, 0u, &vmo);
   if (status != ZX_OK) {
@@ -156,20 +202,29 @@
     result = new VirtualMemory(region, region, region);
   }
   zx_handle_close(vmo);
+
+#if defined(DART_COMPRESSED_POINTERS)
+  if (!is_executable) {
+    uword offset = result->start() - compressed_heap_base_;
+    ASSERT(offset < kCompressedHeapSize);
+  }
+#endif  // defined(DART_COMPRESSED_POINTERS)
+
   return result;
 }
 
 VirtualMemory::~VirtualMemory() {
   // Reserved region may be empty due to VirtualMemory::Truncate.
   if (vm_owns_region() && reserved_.size() != 0) {
-    Unmap(zx_vmar_root_self(), reserved_.start(), reserved_.end());
+    Unmap(getVmarForAddress(reserved_.start()), reserved_.start(),
+          reserved_.end());
     LOG_INFO("zx_vmar_unmap(0x%lx, 0x%lx) success\n", reserved_.start(),
              reserved_.size());
 
     const intptr_t alias_offset = AliasOffset();
     if (alias_offset != 0) {
-      Unmap(zx_vmar_root_self(), reserved_.start() + alias_offset,
-            reserved_.end() + alias_offset);
+      Unmap(getVmarForAddress(reserved_.start()),
+            reserved_.start() + alias_offset, reserved_.end() + alias_offset);
       LOG_INFO("zx_vmar_unmap(0x%lx, 0x%lx) success\n",
                reserved_.start() + alias_offset, reserved_.size());
     }
@@ -178,7 +233,7 @@
 
 bool VirtualMemory::FreeSubSegment(void* address, intptr_t size) {
   const uword start = reinterpret_cast<uword>(address);
-  Unmap(zx_vmar_root_self(), start, start + size);
+  Unmap(getVmarForAddress(start), start, start + size);
   LOG_INFO("zx_vmar_unmap(0x%p, 0x%lx) success\n", address, size);
   return true;
 }
@@ -211,8 +266,9 @@
       prot = ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE;
       break;
   }
-  zx_status_t status = zx_vmar_protect(zx_vmar_root_self(), prot, page_address,
-                                       end_address - page_address);
+  zx_status_t status =
+      zx_vmar_protect(getVmarForAddress(page_address), prot, page_address,
+                      end_address - page_address);
   LOG_INFO("zx_vmar_protect(%u, 0x%lx, 0x%lx)\n", prot, page_address,
            end_address - page_address);
   if (status != ZX_OK) {
diff --git a/tools/VERSION b/tools/VERSION
index 176ee19..e1365df 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 101
+PRERELEASE 102
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/gn.py b/tools/gn.py
index 336b1df..6f2b0c1 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -331,7 +331,10 @@
                     "Cross-compilation to %s is not supported on host os %s." %
                     (os_name, HOST_OS))
                 return False
-            if not arch in ['ia32', 'x64', 'arm', 'arm_x64', 'armv6', 'arm64']:
+            if not arch in [
+                    'ia32', 'x64', 'arm', 'arm_x64', 'armv6', 'arm64', 'x64c',
+                    'arm64c'
+            ]:
                 print(
                     "Cross-compilation to %s is not supported for architecture %s."
                     % (os_name, arch))
@@ -342,7 +345,7 @@
                     "Cross-compilation to %s is not supported on host os %s." %
                     (os_name, HOST_OS))
                 return False
-            if arch != 'x64' and arch != 'arm64':
+            if not arch in ['x64', 'arm64', 'x64c', 'arm64c']:
                 print(
                     "Cross-compilation to %s is not supported for architecture %s."
                     % (os_name, arch))