Version 3.12.0-60.0.dev

Merge 81c62ce1ddf07c0b68d07bd9de9f492038a504e3 into dev
diff --git a/DEPS b/DEPS
index 241be4d..dfa08e2 100644
--- a/DEPS
+++ b/DEPS
@@ -147,7 +147,7 @@
   "material_color_utilities_rev": "799b6ba2f3f1c28c67cc7e0b4f18e0c7d7f3c03e",
   "native_rev": "2f33e1af716668ab79346fdded6fa3f05ffd827b", # rolled manually while record_use is experimental
   "protobuf_rev": "9e30258e0aa6a6430ee36c84b75308a9702fde42",
-  "pub_rev": "b21ac685bc64f6e81050ec0093aa83543d66e2fd", # rolled manually
+  "pub_rev": "db5c3c06b21098fcf7e9e5acb8a9e6f5dd15b2fe", # rolled manually
   "shelf_rev": "dd830a0338b31bee92fe7ebc20b9bb963403b6b0",
   "sync_http_rev": "6666fff944221891182e1f80bf56569338164d72",
   "tar_rev": "13479f7c2a18f499e840ad470cfcca8c579f6909",
diff --git a/docs/gsoc/Dart-GSoC-2026-Project-Ideas.md b/docs/gsoc/Dart-GSoC-2026-Project-Ideas.md
index da4526c..4d75721 100644
--- a/docs/gsoc/Dart-GSoC-2026-Project-Ideas.md
+++ b/docs/gsoc/Dart-GSoC-2026-Project-Ideas.md
@@ -1,5 +1,5 @@
 > [!info]
-> **Google Summer of Code 2026 is currently accepting applications until April 8, 2026.**
+> **Google Summer of Code 2026 is currently accepting applications until March 31st, 2026.**
 
 The list of accepted projects will be announced on [summerofcode.withgoogle.com](https://summerofcode.withgoogle.com/organizations/).
 
@@ -31,7 +31,7 @@
 
 Applications can be submitted through the [summerofcode.withgoogle.com](https://summerofcode.withgoogle.com/) website. Applicants are encouraged to submit draft proposals, linking to Google Docs with permission for mentors to comment. See also the [contributor guide](https://google.github.io/gsocguides/student/writing-a-proposal) on writing a proposal.
 
-**IMPORTANT**: Remember to submit _final proposals_ before [the April 8th deadline](https://developers.google.com/open-source/gsoc/timeline).
+**IMPORTANT**: Remember to submit _final proposals_ before [the March 31st deadline](https://developers.google.com/open-source/gsoc/timeline).
 
 ## TODO: More ideas as they come!
 
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 e54ded5..ee44075 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
@@ -311,7 +311,9 @@
   void assignMatchedPatternVariable(Variable variable, int promotionKey);
 
   /// Call this method when visiting a boolean literal expression.
-  void booleanLiteral(Expression expression, bool value);
+  ///
+  /// Returns the expression info for the boolean literal.
+  ExpressionInfo booleanLiteral(bool value);
 
   /// Call this method just after visiting the target of a cascade expression.
   ///
@@ -366,13 +368,13 @@
   /// Call this method when finishing the visit of a conditional expression
   /// ("?:").
   ///
-  /// [elseExpression] should be the expression following the ":", and
-  /// [conditionalExpression] should be the whole conditional expression.
+  /// [elseExpression] should be the expression following the ":".
   /// [elseType] should be the static type of the expression following the ":",
   /// and [conditionalExpressionType] should be the static type of the whole
   /// conditional expression.
-  void conditional_end(
-    Expression conditionalExpression,
+  ///
+  /// Returns the expression info for the whole conditional expression.
+  ExpressionInfo conditional_end(
     SharedTypeView conditionalExpressionType,
     Expression elseExpression,
     SharedTypeView elseType,
@@ -482,8 +484,9 @@
   /// [equalityOperand_end] for the left and right operands. [leftOperandType]
   /// and [rightOperandType] should be the static types of the left and right
   /// operands.
-  void equalityOperation_end(
-    Expression wholeExpression,
+  ///
+  /// Returns the expression info for the `==` or `!=` expression.
+  ExpressionInfo? equalityOperation_end(
     ExpressionInfo? leftOperandInfo,
     SharedTypeView leftOperandType,
     ExpressionInfo? rightOperandInfo,
@@ -769,13 +772,13 @@
 
   /// Call this method after visiting the LHS of an "is" expression.
   ///
-  /// [isExpression] should be the complete expression. [subExpression] should
-  /// be the expression to which the "is" check was applied, and
-  /// [subExpressionType] should be its static type. [isNot] should be a
-  /// boolean indicating whether this is an "is" or an "is!" expression.
+  /// [subExpression] should be the expression to which the "is" check was
+  /// applied, and [subExpressionType] should be its static type. [isNot] should
+  /// be a boolean indicating whether this is an "is" or an "is!" expression.
   /// [checkedType] should be the type being checked.
-  void isExpression_end(
-    Expression isExpression,
+  ///
+  /// Returns the expression info for the complete "is" expression.
+  ExpressionInfo? isExpression_end(
     Expression subExpression,
     bool isNot, {
     required SharedTypeView subExpressionType,
@@ -806,11 +809,11 @@
   /// Call this method after visiting the RHS of a logical binary operation
   /// ("||" or "&&").
   ///
-  /// [wholeExpression] should be the whole logical binary expression.
   /// [rightOperand] should be the RHS. [isAnd] should indicate whether the
   /// logical operator is "&&" or "||".
-  void logicalBinaryOp_end(
-    Expression wholeExpression,
+  ///
+  /// Returns the expression info for the whole logical binary expression.
+  ExpressionInfo logicalBinaryOp_end(
     Expression rightOperand, {
     required bool isAnd,
   });
@@ -884,7 +887,9 @@
   /// Call this method when encountering an expression that is a `null` literal.
   ///
   /// [type] should be the static type of the literal (i.e. the type `Null`).
-  void nullLiteral(Expression expression, SharedTypeView type);
+  ///
+  /// Returns the expression info for the null literal.
+  ExpressionInfo nullLiteral(SharedTypeView type);
 
   /// Call this method just after visiting a parenthesized expression.
   ///
@@ -938,7 +943,14 @@
 
   /// Call this method when writing to the [variable] with type [writtenType] in
   /// a postfix increment or decrement operation.
-  void postIncDec(Node node, Variable variable, SharedTypeView writtenType);
+  ///
+  /// Returns the expression info for the full post increment or decrement
+  /// expression.
+  ExpressionInfo? postIncDec(
+    Node node,
+    Variable variable,
+    SharedTypeView writtenType,
+  );
 
   /// The type that a property named [propertyName] is promoted to, if
   /// the property is currently promoted.
@@ -1214,13 +1226,13 @@
   /// 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. [staticType]
-  /// should be the static type of `this`.
+  /// [staticType] should be the static type of `this`.
   ///
   /// [isSuper] indicates whether the expression that was visited was the
   /// pseudo-expression `super`.
-  void thisOrSuper(
-    Expression expression,
+  ///
+  /// Returns the expression info for the `this` or `super` expression.
+  ExpressionInfo thisOrSuper(
     SharedTypeView staticType, {
     required bool isSuper,
   });
@@ -1327,9 +1339,12 @@
   /// Call this method when encountering an expression that reads the value of
   /// a variable.
   ///
-  /// If the variable's type is currently promoted, the promoted type is
-  /// returned. Otherwise `null` is returned.
-  SharedTypeView? variableRead(Expression expression, Variable variable);
+  /// Returns a pair:
+  /// - If the variable's type is currently promoted, the first element of the
+  ///   pair is the promoted type. Otherwise it is `null`.
+  /// - The second element of the pair is the expression info for the variable
+  ///   read.
+  (SharedTypeView?, ExpressionInfo) variableRead(Variable variable);
 
   /// Call this method after visiting the condition part of a "while" statement.
   ///
@@ -1415,9 +1430,11 @@
   /// source code (this happens, for example, with compound assignments and with
   /// for-each loops).
   ///
+  /// Returns the expression info for the full assignment expression.
+  ///
   /// This method should not be used for the implicit write to a non-final
   /// variable in its initializer; in that case, use [initialize] instead.
-  void write(
+  ExpressionInfo? write(
     Node node,
     Variable variable,
     SharedTypeView writtenType,
@@ -1526,10 +1543,12 @@
   }
 
   @override
-  void booleanLiteral(Expression expression, bool value) {
-    _wrap(
-      'booleanLiteral($expression, $value)',
-      () => _wrapped.booleanLiteral(expression, value),
+  ExpressionInfo booleanLiteral(bool value) {
+    return _wrap(
+      'booleanLiteral($value)',
+      () => _wrapped.booleanLiteral(value),
+      isQuery: true,
+      isPure: false,
     );
   }
 
@@ -1582,21 +1601,21 @@
   }
 
   @override
-  void conditional_end(
-    Expression conditionalExpression,
+  ExpressionInfo conditional_end(
     SharedTypeView conditionalExpressionType,
     Expression elseExpression,
     SharedTypeView elseType,
   ) {
-    _wrap(
-      'conditional_end($conditionalExpression, $conditionalExpressionType, '
+    return _wrap(
+      'conditional_end($conditionalExpressionType, '
       '$elseExpression, $elseType)',
       () => _wrapped.conditional_end(
-        conditionalExpression,
         conditionalExpressionType,
         elseExpression,
         elseType,
       ),
+      isQuery: true,
+      isPure: false,
     );
   }
 
@@ -1711,26 +1730,26 @@
   );
 
   @override
-  void equalityOperation_end(
-    Expression wholeExpression,
+  ExpressionInfo? equalityOperation_end(
     ExpressionInfo? leftOperandInfo,
     SharedTypeView leftOperandType,
     ExpressionInfo? rightOperandInfo,
     SharedTypeView rightOperandType, {
     bool notEqual = false,
   }) {
-    _wrap(
-      'equalityOperation_end($wholeExpression, $leftOperandInfo, '
+    return _wrap(
+      'equalityOperation_end($leftOperandInfo, '
       '$leftOperandType, $rightOperandInfo, $rightOperandType, notEqual: '
       '$notEqual)',
       () => _wrapped.equalityOperation_end(
-        wholeExpression,
         leftOperandInfo,
         leftOperandType,
         rightOperandInfo,
         rightOperandType,
         notEqual: notEqual,
       ),
+      isQuery: true,
+      isPure: false,
     );
   }
 
@@ -1968,23 +1987,23 @@
   }
 
   @override
-  void isExpression_end(
-    Expression isExpression,
+  ExpressionInfo? isExpression_end(
     Expression subExpression,
     bool isNot, {
     required SharedTypeView subExpressionType,
     required SharedTypeView checkedType,
   }) {
-    _wrap(
-      'isExpression_end($isExpression, $subExpression, $isNot, '
+    return _wrap(
+      'isExpression_end($subExpression, $isNot, '
       'subExpressionType: $subExpressionType, checkedType: $checkedType)',
       () => _wrapped.isExpression_end(
-        isExpression,
         subExpression,
         isNot,
         subExpressionType: subExpressionType,
         checkedType: checkedType,
       ),
+      isQuery: true,
+      isPure: false,
     );
   }
 
@@ -2032,18 +2051,15 @@
   }
 
   @override
-  void logicalBinaryOp_end(
-    Expression wholeExpression,
+  ExpressionInfo logicalBinaryOp_end(
     Expression rightOperand, {
     required bool isAnd,
   }) {
-    _wrap(
-      'logicalBinaryOp_end($wholeExpression, $rightOperand, isAnd: $isAnd)',
-      () => _wrapped.logicalBinaryOp_end(
-        wholeExpression,
-        rightOperand,
-        isAnd: isAnd,
-      ),
+    return _wrap(
+      'logicalBinaryOp_end($rightOperand, isAnd: $isAnd)',
+      () => _wrapped.logicalBinaryOp_end(rightOperand, isAnd: isAnd),
+      isQuery: true,
+      isPure: false,
     );
   }
 
@@ -2117,7 +2133,7 @@
 
   @override
   void nullAwareAccess_rightBegin(
-    Expression? target,
+    Expression target,
     SharedTypeView targetType, {
     Variable? guardVariable,
   }) {
@@ -2183,10 +2199,12 @@
   }
 
   @override
-  void nullLiteral(Expression expression, SharedTypeView type) {
-    _wrap(
-      'nullLiteral($expression, $type)',
-      () => _wrapped.nullLiteral(expression, type),
+  ExpressionInfo nullLiteral(SharedTypeView type) {
+    return _wrap(
+      'nullLiteral($type)',
+      () => _wrapped.nullLiteral(type),
+      isQuery: true,
+      isPure: false,
     );
   }
 
@@ -2261,10 +2279,16 @@
   }
 
   @override
-  void postIncDec(Node node, Variable variable, SharedTypeView writtenType) {
-    _wrap(
+  ExpressionInfo? postIncDec(
+    Node node,
+    Variable variable,
+    SharedTypeView writtenType,
+  ) {
+    return _wrap(
       'postIncDec()',
       () => _wrapped.postIncDec(node, variable, writtenType),
+      isQuery: true,
+      isPure: false,
     );
   }
 
@@ -2487,14 +2511,15 @@
   }
 
   @override
-  void thisOrSuper(
-    Expression expression,
+  ExpressionInfo thisOrSuper(
     SharedTypeView staticType, {
     required bool isSuper,
   }) {
     return _wrap(
-      'thisOrSuper($expression, $staticType, isSuper: $isSuper)',
-      () => _wrapped.thisOrSuper(expression, staticType, isSuper: isSuper),
+      'thisOrSuper($staticType, isSuper: $isSuper)',
+      () => _wrapped.thisOrSuper(staticType, isSuper: isSuper),
+      isQuery: true,
+      isPure: false,
     );
   }
 
@@ -2578,10 +2603,10 @@
   }
 
   @override
-  SharedTypeView? variableRead(Expression expression, Variable variable) {
+  (SharedTypeView?, ExpressionInfo) variableRead(Variable variable) {
     return _wrap(
-      'variableRead($expression, $variable)',
-      () => _wrapped.variableRead(expression, variable),
+      'variableRead($variable)',
+      () => _wrapped.variableRead(variable),
       isQuery: true,
       isPure: false,
     );
@@ -2635,15 +2660,17 @@
   }
 
   @override
-  void write(
+  ExpressionInfo? write(
     Node node,
     Variable variable,
     SharedTypeView writtenType,
     Expression? writtenExpression,
   ) {
-    _wrap(
+    return _wrap(
       'write($node, $variable, $writtenType, $writtenExpression)',
       () => _wrapped.write(node, variable, writtenType, writtenExpression),
+      isQuery: true,
+      isPure: false,
     );
   }
 
@@ -2736,7 +2763,7 @@
   /// be called once upon reaching each `?.`, but [nullAwareAccess_end] should
   /// not be called until after processing the method call to `z(x)`.
   void nullAwareAccess_rightBegin(
-    Expression? target,
+    Expression target,
     SharedTypeView targetType, {
     Variable? guardVariable,
   });
@@ -5207,22 +5234,21 @@
   }
 
   @override
-  void booleanLiteral(Expression expression, bool value) {
+  ExpressionInfo booleanLiteral(bool value) {
     FlowModel unreachable = _current.setUnreachable();
-    _storeExpressionInfo(
-      expression,
-      value
-          ? new ExpressionInfo(
-              type: boolType,
-              ifTrue: _current,
-              ifFalse: unreachable,
-            )
-          : new ExpressionInfo(
-              type: boolType,
-              ifTrue: unreachable,
-              ifFalse: _current,
-            ),
-    );
+    if (value) {
+      return new ExpressionInfo(
+        type: boolType,
+        ifTrue: _current,
+        ifFalse: unreachable,
+      );
+    } else {
+      return new ExpressionInfo(
+        type: boolType,
+        ifTrue: unreachable,
+        ifFalse: _current,
+      );
+    }
   }
 
   @override
@@ -5258,20 +5284,14 @@
     _cascadeTargetStack.add(
       _makeTemporaryReference(ssaNode, promotedTargetType),
     );
-    // Calling `_getExpressionReference` had the effect of clearing
-    // `_expressionReference` (because normally the caller doesn't pass the same
-    // expression to flow analysis twice, so the expression reference isn't
-    // needed anymore). However, in the case of null-aware cascades, this call
-    // will be followed by a call to [nullAwareAccess_rightBegin], and the
-    // expression reference will be needed again. So store it back.
-    if (expressionReference != null) {
-      _storeExpressionInfo(target, expressionReference);
-    }
     if (isNullAware) {
-      _nullAwareAccess_rightBegin(
+      _storeExpressionInfo(
         target,
-        targetType,
-        guardVariable: guardVariable,
+        _nullAwareAccess_rightBegin(
+          expressionReference,
+          targetType,
+          guardVariable: guardVariable,
+        ),
       );
     }
     return promotedTargetType;
@@ -5311,8 +5331,7 @@
   }
 
   @override
-  void conditional_end(
-    Expression conditionalExpression,
+  ExpressionInfo conditional_end(
     SharedTypeView conditionalExpressionType,
     Expression elseExpression,
     SharedTypeView elseType,
@@ -5325,13 +5344,10 @@
         _makeTrivialExpressionInfo(elseType);
     FlowModel elseModel = _current;
     _current = _join(thenModel, elseModel).unsplit();
-    _storeExpressionInfo(
-      conditionalExpression,
-      new ExpressionInfo(
-        type: conditionalExpressionType,
-        ifTrue: _join(thenInfo.ifTrue, elseInfo.ifTrue).unsplit(),
-        ifFalse: _join(thenInfo.ifFalse, elseInfo.ifFalse).unsplit(),
-      ),
+    return new ExpressionInfo(
+      type: conditionalExpressionType,
+      ifTrue: _join(thenInfo.ifTrue, elseInfo.ifTrue).unsplit(),
+      ifFalse: _join(thenInfo.ifFalse, elseInfo.ifFalse).unsplit(),
     );
   }
 
@@ -5462,8 +5478,7 @@
       _getExpressionInfo(operand);
 
   @override
-  void equalityOperation_end(
-    Expression wholeExpression,
+  ExpressionInfo? equalityOperation_end(
     ExpressionInfo? leftOperandInfo,
     SharedTypeView leftOperandType,
     ExpressionInfo? rightOperandInfo,
@@ -5485,12 +5500,12 @@
         // Both operands are known by flow analysis to compare equal, so the
         // whole expression behaves equivalently to a boolean (either `true` or
         // `false` depending whether the check uses the `!=` operator).
-        booleanLiteral(wholeExpression, !notEqual);
+        return booleanLiteral(!notEqual);
       case _GuaranteedNotEqual():
         // Both operands are known by flow analysis to compare unequal, so the
         // whole expression behaves equivalently to a boolean (either `true` or
         // `false` depending whether the check uses the `!=` operator).
-        booleanLiteral(wholeExpression, notEqual);
+        return booleanLiteral(notEqual);
 
       // SAFETY: we can assume `reference` is a `_Reference<Type>` because we
       // require clients not to mix data obtained from different
@@ -5499,7 +5514,7 @@
         if (reference == null) {
           // One side of the equality check is `null`, but the other side is not
           // a promotable reference.  So there's no promotion to do.
-          return;
+          return null;
         }
         // The equality check is a null check of something potentially
         // promotable (e.g. a local variable).  Record the necessary information
@@ -5509,19 +5524,15 @@
           this,
           reference,
         );
-        _storeExpressionInfo(
-          wholeExpression,
-          notEqual ? equalityInfo : equalityInfo._invert(),
-        );
+        return notEqual ? equalityInfo : equalityInfo._invert();
 
       case _NoEqualityInformation():
-      // Since flow analysis can't garner any information from this equality
-      // check, nothing needs to be done; by not calling `_storeExpressionInfo`,
-      // we ensure that if `_getExpressionInfo` is later called on this
-      // expression, `null` will be returned.  That means that if this
-      // expression winds up being used for a conditional branch, flow analysis
-      // will consider both code paths reachable and won't perform any
-      // promotions on either path.
+        // Since flow analysis can't garner any information from this equality
+        // check, nothing needs to be done; by not returning any expression
+        // info, we ensure that if this expression winds up being used for a
+        // conditional branch, flow analysis will consider both code paths
+        // reachable and won't perform any promotions on either path.
+        return null;
     }
   }
 
@@ -5812,8 +5823,7 @@
   }
 
   @override
-  void isExpression_end(
-    Expression isExpression,
+  ExpressionInfo? isExpression_end(
     Expression subExpression,
     bool isNot, {
     required SharedTypeView subExpressionType,
@@ -5824,7 +5834,7 @@
           staticType: subExpressionType,
           checkedType: checkedType,
         )) {
-      booleanLiteral(isExpression, isNot);
+      return booleanLiteral(isNot);
     } else {
       _Reference? subExpressionReference = _getExpressionReference(
         _getExpressionInfo(subExpression),
@@ -5835,15 +5845,14 @@
           subExpressionReference,
           checkedType,
         );
-        _storeExpressionInfo(
-          isExpression,
-          isNot ? expressionInfo._invert() : expressionInfo,
-        );
+        return isNot ? expressionInfo._invert() : expressionInfo;
       } else if (_isTypeCheckGuaranteedToSucceedWithSoundNullSafety(
         staticType: subExpressionType,
         checkedType: checkedType,
       )) {
-        booleanLiteral(isExpression, !isNot);
+        return booleanLiteral(!isNot);
+      } else {
+        return null;
       }
     }
   }
@@ -5927,8 +5936,7 @@
   }
 
   @override
-  void logicalBinaryOp_end(
-    Expression wholeExpression,
+  ExpressionInfo logicalBinaryOp_end(
     Expression rightOperand, {
     required bool isAnd,
   }) {
@@ -5947,13 +5955,10 @@
       falseResult = rhsInfo.ifFalse;
     }
     _current = _join(trueResult, falseResult).unsplit();
-    _storeExpressionInfo(
-      wholeExpression,
-      new ExpressionInfo(
-        type: boolType,
-        ifTrue: trueResult.unsplit(),
-        ifFalse: falseResult.unsplit(),
-      ),
+    return new ExpressionInfo(
+      type: boolType,
+      ifTrue: trueResult.unsplit(),
+      ifFalse: falseResult.unsplit(),
     );
   }
 
@@ -6043,14 +6048,17 @@
 
   @override
   void nullAwareAccess_rightBegin(
-    Expression? target,
+    Expression target,
     SharedTypeView targetType, {
     Variable? guardVariable,
   }) {
-    _nullAwareAccess_rightBegin(
+    _storeExpressionInfo(
       target,
-      targetType,
-      guardVariable: guardVariable,
+      _nullAwareAccess_rightBegin(
+        _getExpressionInfo(target),
+        targetType,
+        guardVariable: guardVariable,
+      ),
     );
   }
 
@@ -6136,11 +6144,8 @@
   void nullCheckOrAssertPattern_end() {}
 
   @override
-  void nullLiteral(Expression expression, SharedTypeView type) {
-    _storeExpressionInfo(
-      expression,
-      new _NullInfo(model: _current, type: type),
-    );
+  ExpressionInfo nullLiteral(SharedTypeView type) {
+    return new _NullInfo(model: _current, type: type);
   }
 
   @override
@@ -6209,8 +6214,12 @@
   }
 
   @override
-  void postIncDec(Node node, Variable variable, SharedTypeView writtenType) {
-    _write(node, variable, writtenType, null, isPostfixIncDec: true);
+  ExpressionInfo? postIncDec(
+    Node node,
+    Variable variable,
+    SharedTypeView writtenType,
+  ) {
+    return _write(node, variable, writtenType, null, isPostfixIncDec: true);
   }
 
   @override
@@ -6608,16 +6617,11 @@
   }
 
   @override
-  void thisOrSuper(
-    Expression expression,
+  ExpressionInfo thisOrSuper(
     SharedTypeView staticType, {
     required bool isSuper,
   }) {
-    TrivialVariableReference reference = _thisOrSuperReference(
-      staticType,
-      isSuper: isSuper,
-    );
-    _storeExpressionInfo(expression, reference);
+    return _thisOrSuperReference(staticType, isSuper: isSuper);
   }
 
   @override
@@ -6742,7 +6746,7 @@
       const [];
 
   @override
-  SharedTypeView? variableRead(Expression expression, Variable variable) {
+  (SharedTypeView?, ExpressionInfo) variableRead(Variable variable) {
     SharedTypeView unpromotedType = operations.variableType(variable);
     int variableKey = promotionKeyStore.keyForVariable(variable);
     PromotionModel? promotionModel = _current.promotionInfo?.get(
@@ -6763,8 +6767,7 @@
           this,
           _current,
         );
-    _storeExpressionInfo(expression, expressionInfo);
-    return promotionModel.promotedTypes.lastOrNull;
+    return (promotionModel.promotedTypes.lastOrNull, expressionInfo);
   }
 
   @override
@@ -6832,13 +6835,18 @@
   }
 
   @override
-  void write(
+  ExpressionInfo? write(
     Node node,
     Variable variable,
     SharedTypeView writtenType,
     Expression? writtenExpression,
   ) {
-    _write(node, variable, writtenType, _getExpressionInfo(writtenExpression));
+    return _write(
+      node,
+      variable,
+      writtenType,
+      _getExpressionInfo(writtenExpression),
+    );
   }
 
   /// Computes a [FlowModel] representing the state of execution after the
@@ -7542,16 +7550,14 @@
   ExpressionInfo _makeTrivialExpressionInfo(SharedTypeView type) =>
       new ExpressionInfo.trivial(model: _current, type: type);
 
-  void _nullAwareAccess_rightBegin(
-    Expression? target,
+  ExpressionInfo? _nullAwareAccess_rightBegin(
+    ExpressionInfo? targetInfo,
     SharedTypeView targetType, {
     required Variable? guardVariable,
   }) {
     _current = _current.split();
     FlowModel shortcutControlPath = _current;
-    _Reference? targetReference = _getExpressionReference(
-      _getExpressionInfo(target),
-    );
+    _Reference? targetReference = _getExpressionReference(targetInfo);
     if (targetReference != null) {
       _current = _current.tryMarkNonNullable(this, targetReference).ifTrue;
     }
@@ -7571,6 +7577,7 @@
     }
     _stack.add(new _NullAwareAccessContext(shortcutControlPath));
     SsaNode? targetSsaNode;
+    ExpressionInfo? nullAwareExpressionInfo = targetReference;
     if (typeAnalyzerOptions.soundFlowAnalysisEnabled) {
       // Pick up the target SSA node so that it can be used for field promotion.
       targetSsaNode = targetReference?.ssaNode;
@@ -7578,7 +7585,7 @@
       // Field promotion was broken for null-aware field accesses prior to the
       // implementation of sound flow analysis. So to replicate the bug, destroy
       // the target reference so that it can't be used for field promotion.
-      if (target != null) _storeExpressionInfo(target, null);
+      nullAwareExpressionInfo = null;
     }
     if (guardVariable != null) {
       // Promote the guard variable as well.
@@ -7596,6 +7603,7 @@
         ),
       );
     }
+    return nullAwareExpressionInfo;
   }
 
   /// Computes an updated flow model representing the result of a null check
@@ -7749,7 +7757,7 @@
   ///
   /// If [isPostfixIncDec] is `true`, the [node] is a postfix expression and we
   /// won't store information about [variable].
-  void _write(
+  ExpressionInfo? _write(
     Node node,
     Variable variable,
     SharedTypeView writtenType,
@@ -7774,12 +7782,13 @@
     );
 
     // Update the type of the variable for looking up the write expression.
+    TrivialVariableReference? reference;
     if (typeAnalyzerOptions.inferenceUpdate4Enabled &&
         node is Expression &&
         !isPostfixIncDec) {
-      _Reference reference = _variableReference(variableKey, unpromotedType);
-      _storeExpressionInfo(node, reference);
+      reference = _variableReference(variableKey, unpromotedType);
     }
+    return reference;
   }
 }
 
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index 7d354f0..c2d33d4 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -5888,10 +5888,13 @@
     Expression postIncDecExpression,
     Type writtenType,
   ) {
-    h.flow.postIncDec(
+    h.flow.storeExpressionInfo(
       postIncDecExpression,
-      variable,
-      SharedTypeView(writtenType),
+      h.flow.postIncDec(
+        postIncDecExpression,
+        variable,
+        SharedTypeView(writtenType),
+      ),
     );
   }
 
@@ -5902,11 +5905,14 @@
     Type writtenType,
     Expression? rhs,
   ) {
-    h.flow.write(
+    h.flow.storeExpressionInfo(
       assignmentExpression,
-      variable,
-      SharedTypeView(writtenType),
-      rhs,
+      h.flow.write(
+        assignmentExpression,
+        variable,
+        SharedTypeView(writtenType),
+        rhs,
+      ),
     );
   }
 }
@@ -6507,16 +6513,21 @@
     }
     var rightType = analyzeExpression(rhs, operations.unknownType).type;
     if (isEquals) {
-      flow.equalityOperation_end(
+      flow.storeExpressionInfo(
         node,
-        leftInfo,
-        leftType,
-        flow.equalityOperand_end(rhs),
-        rightType,
-        notEqual: isNot,
+        flow.equalityOperation_end(
+          leftInfo,
+          leftType,
+          flow.equalityOperand_end(rhs),
+          rightType,
+          notEqual: isNot,
+        ),
       );
     } else if (isLogical) {
-      flow.logicalBinaryOp_end(node, rhs, isAnd: isAnd);
+      flow.storeExpressionInfo(
+        node,
+        flow.logicalBinaryOp_end(rhs, isAnd: isAnd),
+      );
     }
     return new ExpressionTypeAnalysisResult(type: operations.boolType);
   }
@@ -6528,7 +6539,7 @@
   }
 
   Type analyzeBoolLiteral(Expression node, bool value) {
-    flow.booleanLiteral(node, value);
+    flow.storeExpressionInfo(node, flow.booleanLiteral(value));
     return operations.boolType.unwrapTypeView();
   }
 
@@ -6549,7 +6560,10 @@
     flow.conditional_elseBegin(ifTrue, ifTrueType);
     var ifFalseType = analyzeExpression(ifFalse, operations.unknownType).type;
     var lubType = operations.lub(ifTrueType, ifFalseType);
-    flow.conditional_end(node, lubType, ifFalse, ifFalseType);
+    flow.storeExpressionInfo(
+      node,
+      flow.conditional_end(lubType, ifFalse, ifFalseType),
+    );
     return new ExpressionTypeAnalysisResult(type: lubType);
   }
 
@@ -6697,7 +6711,7 @@
   }
 
   ExpressionTypeAnalysisResult analyzeNullLiteral(Expression node) {
-    flow.nullLiteral(node, SharedTypeView(nullType));
+    flow.storeExpressionInfo(node, flow.nullLiteral(SharedTypeView(nullType)));
     return new ExpressionTypeAnalysisResult(type: SharedTypeView(nullType));
   }
 
@@ -6743,7 +6757,10 @@
 
   ExpressionTypeAnalysisResult analyzeThis(Expression node) {
     var thisType = this.thisType;
-    flow.thisOrSuper(node, SharedTypeView(thisType), isSuper: false);
+    flow.storeExpressionInfo(
+      node,
+      flow.thisOrSuper(SharedTypeView(thisType), isSuper: false),
+    );
     return new ExpressionTypeAnalysisResult(type: SharedTypeView(thisType));
   }
 
@@ -6841,12 +6858,14 @@
       expression,
       operations.unknownType,
     ).type;
-    flow.isExpression_end(
+    flow.storeExpressionInfo(
       node,
-      expression,
-      isInverted,
-      subExpressionType: subExpressionType,
-      checkedType: SharedTypeView(type),
+      flow.isExpression_end(
+        expression,
+        isInverted,
+        subExpressionType: subExpressionType,
+        checkedType: SharedTypeView(type),
+      ),
     );
     return new ExpressionTypeAnalysisResult(type: operations.boolType);
   }
@@ -6856,7 +6875,8 @@
     Var variable,
     void Function(Type?)? callback,
   ) {
-    var promotedType = flow.variableRead(node, variable);
+    var (promotedType, expressionInfo) = flow.variableRead(variable);
+    flow.storeExpressionInfo(node, expressionInfo);
     callback?.call(promotedType?.unwrapTypeView());
     return new ExpressionTypeAnalysisResult(
       type: promotedType ?? SharedTypeView(variable.type),
diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
index 1708d81..c02e74d 100644
--- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -268,9 +268,6 @@
     Name name,
   ) {
     var interface = getInterface(element);
-    if (element is ExtensionTypeElementImpl) {
-      return interface.redeclared[name];
-    }
     return interface.overridden[name];
   }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index 4e52587..29f9aaf 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -106,11 +106,14 @@
 
     if (flow != null) {
       if (writeElement2 is PromotableElementImpl) {
-        flow.write(
+        flow.storeExpressionInfo(
           node,
-          writeElement2,
-          SharedTypeView(node.typeOrThrow),
-          hasRead ? null : right,
+          flow.write(
+            node,
+            writeElement2,
+            SharedTypeView(node.typeOrThrow),
+            hasRead ? null : right,
+          ),
         );
       }
       if (isIfNull) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index 596bf48..f553976 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -124,13 +124,15 @@
     var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(right);
 
     if (!leftExtensionOverride) {
-      flow?.equalityOperation_end(
+      flow?.storeExpressionInfo(
         node,
-        leftInfo,
-        SharedTypeView(left.typeOrThrow),
-        flow.equalityOperand_end(right),
-        SharedTypeView(right.typeOrThrow),
-        notEqual: notEqual,
+        flow.equalityOperation_end(
+          leftInfo,
+          SharedTypeView(left.typeOrThrow),
+          flow.equalityOperand_end(right),
+          SharedTypeView(right.typeOrThrow),
+          notEqual: notEqual,
+        ),
       );
     }
 
@@ -272,7 +274,10 @@
     );
 
     _resolver.nullSafetyDeadCodeVerifier.flowEnd(right);
-    flow?.logicalBinaryOp_end(node, right, isAnd: true);
+    flow?.storeExpressionInfo(
+      node,
+      flow.logicalBinaryOp_end(right, isAnd: true),
+    );
 
     _checkNonBoolOperand(left, '&&', whyNotPromoted: leftWhyNotPromoted);
     _checkNonBoolOperand(right, '&&', whyNotPromoted: rightWhyNotPromoted);
@@ -306,7 +311,10 @@
     );
 
     _resolver.nullSafetyDeadCodeVerifier.flowEnd(right);
-    flow?.logicalBinaryOp_end(node, right, isAnd: false);
+    flow?.storeExpressionInfo(
+      node,
+      flow.logicalBinaryOp_end(right, isAnd: false),
+    );
 
     _checkNonBoolOperand(left, '||', whyNotPromoted: leftWhyNotPromoted);
     _checkNonBoolOperand(right, '||', whyNotPromoted: rightWhyNotPromoted);
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 579ac43..d5f24df 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -296,12 +296,14 @@
     var expression = node.expression;
     var typeAnnotation = node.type;
 
-    flow!.isExpression_end(
+    flow!.storeExpressionInfo(
       node,
-      expression,
-      node.notOperator != null,
-      subExpressionType: SharedTypeView(expression.typeOrThrow),
-      checkedType: SharedTypeView(typeAnnotation.typeOrThrow),
+      flow!.isExpression_end(
+        expression,
+        node.notOperator != null,
+        subExpressionType: SharedTypeView(expression.typeOrThrow),
+        checkedType: SharedTypeView(typeAnnotation.typeOrThrow),
+      ),
     );
   }
 
@@ -1307,10 +1309,16 @@
   @override
   TypeImpl getType(SimpleIdentifierImpl node, {required bool isRead}) {
     var variable = node.element as InternalVariableElement;
-    if (variable is PromotableElementImpl) {
-      var promotedType = isRead
-          ? _manager.flow?.variableRead(node, variable)
-          : _manager.flow?.promotedType(variable);
+    var flow = _manager.flow;
+    if (variable is PromotableElementImpl && flow != null) {
+      SharedTypeView? promotedType;
+      if (isRead) {
+        ExpressionInfo expressionInfo;
+        (promotedType, expressionInfo) = flow.variableRead(variable);
+        flow.storeExpressionInfo(node, expressionInfo);
+      } else {
+        promotedType = flow.promotedType(variable);
+      }
       if (promotedType != null) {
         return promotedType.unwrapTypeView<TypeImpl>();
       }
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
index e53af67..cd36042 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
@@ -570,12 +570,14 @@
     if (identicalArgumentInfo != null) {
       var leftOperandInfo = identicalArgumentInfo[0]!;
       var rightOperandInfo = identicalArgumentInfo[1]!;
-      flow?.equalityOperation_end(
+      flow?.storeExpressionInfo(
         argumentList.parent as ExpressionImpl,
-        leftOperandInfo.expressionInfo,
-        SharedTypeView(leftOperandInfo.staticType),
-        rightOperandInfo.expressionInfo,
-        SharedTypeView(rightOperandInfo.staticType),
+        flow.equalityOperation_end(
+          leftOperandInfo.expressionInfo,
+          SharedTypeView(leftOperandInfo.staticType),
+          rightOperandInfo.expressionInfo,
+          SharedTypeView(rightOperandInfo.staticType),
+        ),
       );
     }
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
index ca5be97..61426f4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
@@ -186,17 +186,23 @@
           if (_resolver.definingLibrary.featureSet.isEnabled(
             Feature.inference_update_4,
           )) {
-            _resolver.flowAnalysis.flow?.postIncDec(
+            _resolver.flowAnalysis.flow?.storeExpressionInfo(
               node,
-              element,
-              SharedTypeView(operatorReturnType),
+              _resolver.flowAnalysis.flow?.postIncDec(
+                node,
+                element,
+                SharedTypeView(operatorReturnType),
+              ),
             );
           } else {
-            _resolver.flowAnalysis.flow?.write(
+            _resolver.flowAnalysis.flow?.storeExpressionInfo(
               node,
-              element,
-              SharedTypeView(operatorReturnType),
-              null,
+              _resolver.flowAnalysis.flow?.write(
+                node,
+                element,
+                SharedTypeView(operatorReturnType),
+                null,
+              ),
             );
           }
         }
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index d35abc8..e2afb29 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -243,11 +243,14 @@
         if (operand is SimpleIdentifier) {
           var element = operand.element;
           if (element is PromotableElementImpl) {
-            _resolver.flowAnalysis.flow?.write(
+            _resolver.flowAnalysis.flow?.storeExpressionInfo(
               node,
-              element,
-              SharedTypeView(staticType),
-              null,
+              _resolver.flowAnalysis.flow?.write(
+                node,
+                element,
+                SharedTypeView(staticType),
+                null,
+              ),
             );
           }
         }
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 1c19433..264cc6b 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2027,7 +2027,10 @@
     TypeImpl contextType = UnknownInferredType.instance,
   }) {
     inferenceLogWriter?.enterExpression(node, contextType);
-    flowAnalysis.flow?.booleanLiteral(node, node.value);
+    flowAnalysis.flow?.storeExpressionInfo(
+      node,
+      flowAnalysis.flow?.booleanLiteral(node.value),
+    );
     checkUnreachableNode(node);
     node.visitChildren(this);
     typeAnalyzer.visitBooleanLiteral(node);
@@ -2207,11 +2210,13 @@
 
     typeAnalyzer.visitConditionalExpression(node, contextType: contextType);
     if (flow != null) {
-      flow.conditional_end(
+      flow.storeExpressionInfo(
         node,
-        SharedTypeView(node.typeOrThrow),
-        elseExpression,
-        SharedTypeView(elseExpression.typeOrThrow),
+        flow.conditional_end(
+          SharedTypeView(node.typeOrThrow),
+          elseExpression,
+          SharedTypeView(elseExpression.typeOrThrow),
+        ),
       );
       nullSafetyDeadCodeVerifier.flowEnd(elseExpression);
     }
@@ -3493,7 +3498,10 @@
     inferenceLogWriter?.enterExpression(node, contextType);
     node.visitChildren(this);
     typeAnalyzer.visitNullLiteral(node as NullLiteralImpl);
-    flowAnalysis.flow?.nullLiteral(node, SharedTypeView(node.typeOrThrow));
+    flowAnalysis.flow?.storeExpressionInfo(
+      node,
+      flowAnalysis.flow?.nullLiteral(SharedTypeView(node.typeOrThrow)),
+    );
     checkUnreachableNode(node);
     inferenceLogWriter?.exitExpression(node);
   }
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 365170d..f43af10 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -255,10 +255,12 @@
 
   void visitSuperExpression(covariant SuperExpressionImpl node) {
     var thisType = _resolver.thisType;
-    _resolver.flowAnalysis.flow?.thisOrSuper(
+    _resolver.flowAnalysis.flow?.storeExpressionInfo(
       node,
-      SharedTypeView(thisType ?? _dynamicType),
-      isSuper: true,
+      _resolver.flowAnalysis.flow?.thisOrSuper(
+        SharedTypeView(thisType ?? _dynamicType),
+        isSuper: true,
+      ),
     );
     if (thisType == null ||
         node.thisOrAncestorOfType<ExtensionDeclaration>() != null) {
@@ -278,10 +280,12 @@
   /// interface of the immediately enclosing class.</blockquote>
   void visitThisExpression(covariant ThisExpressionImpl node) {
     var thisType = _resolver.thisType;
-    _resolver.flowAnalysis.flow?.thisOrSuper(
+    _resolver.flowAnalysis.flow?.storeExpressionInfo(
       node,
-      SharedTypeView(thisType ?? _dynamicType),
-      isSuper: false,
+      _resolver.flowAnalysis.flow?.thisOrSuper(
+        SharedTypeView(thisType ?? _dynamicType),
+        isSuper: false,
+      ),
     );
     if (thisType == null) {
       // TODO(brianwilkerson): Report this error if it hasn't already been
diff --git a/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart b/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
index 222cc25..9f7606d 100644
--- a/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
+++ b/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
@@ -2341,7 +2341,7 @@
 
     var element = library.getExtensionType('B')!;
     _assertGetOverridden(element, 'foo', r'''
-A.foo: void Function()
+<null>
 ''');
   }
 
diff --git a/pkg/analyzer/test/src/summary/elements/extension_type_test.dart b/pkg/analyzer/test/src/summary/elements/extension_type_test.dart
index cedf284..d73950b7 100644
--- a/pkg/analyzer/test/src/summary/elements/extension_type_test.dart
+++ b/pkg/analyzer/test/src/summary/elements/extension_type_test.dart
@@ -5418,105 +5418,6 @@
 ''');
   }
 
-  test_primaryConstructor_formalParameters_kind_requiredPositional_type_fromField_fromImplemented() async {
-    var library = await buildLibrary(r'''
-class A {
-  int get it => 0;
-}
-
-extension type E(it) implements A {}
-''');
-
-    checkElementText(library, r'''
-library
-  reference: <testLibrary>
-  fragments
-    #F0 <testLibraryFragment>
-      element: <testLibrary>
-      classes
-        #F1 class A (nameOffset:6) (firstTokenOffset:0) (offset:6)
-          element: <testLibrary>::@class::A
-          fields
-            #F2 synthetic isOriginGetterSetter it (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6)
-              element: <testLibrary>::@class::A::@field::it
-          constructors
-            #F3 synthetic isOriginImplicitDefault new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6)
-              element: <testLibrary>::@class::A::@constructor::new
-              typeName: A
-          getters
-            #F4 isOriginDeclaration it (nameOffset:20) (firstTokenOffset:12) (offset:20)
-              element: <testLibrary>::@class::A::@getter::it
-      extensionTypes
-        #F5 extension type E (nameOffset:47) (firstTokenOffset:32) (offset:47)
-          element: <testLibrary>::@extensionType::E
-          fields
-            #F6 isOriginDeclaringFormalParameter it (nameOffset:<null>) (firstTokenOffset:<null>) (offset:47)
-              element: <testLibrary>::@extensionType::E::@field::it
-          constructors
-            #F7 isOriginDeclaration isPrimary new (nameOffset:<null>) (firstTokenOffset:47) (offset:47)
-              element: <testLibrary>::@extensionType::E::@constructor::new
-              typeName: E
-              typeNameOffset: 47
-              formalParameters
-                #F8 requiredPositional final this.it (nameOffset:49) (firstTokenOffset:49) (offset:49)
-                  element: <testLibrary>::@extensionType::E::@constructor::new::@formalParameter::it
-          getters
-            #F9 synthetic isOriginVariable it (nameOffset:<null>) (firstTokenOffset:<null>) (offset:47)
-              element: <testLibrary>::@extensionType::E::@getter::it
-  classes
-    class A
-      reference: <testLibrary>::@class::A
-      firstFragment: #F1
-      fields
-        synthetic isOriginGetterSetter it
-          reference: <testLibrary>::@class::A::@field::it
-          firstFragment: #F2
-          type: int
-          getter: <testLibrary>::@class::A::@getter::it
-      constructors
-        synthetic isOriginImplicitDefault new
-          reference: <testLibrary>::@class::A::@constructor::new
-          firstFragment: #F3
-      getters
-        isOriginDeclaration it
-          reference: <testLibrary>::@class::A::@getter::it
-          firstFragment: #F4
-          returnType: int
-          variable: <testLibrary>::@class::A::@field::it
-  extensionTypes
-    extension type E
-      reference: <testLibrary>::@extensionType::E
-      firstFragment: #F5
-      representation: <testLibrary>::@extensionType::E::@field::it
-      primaryConstructor: <testLibrary>::@extensionType::E::@constructor::new
-      typeErasure: int
-      interfaces
-        A
-      fields
-        final hasImplicitType isOriginDeclaringFormalParameter it
-          reference: <testLibrary>::@extensionType::E::@field::it
-          firstFragment: #F6
-          type: int
-          getter: <testLibrary>::@extensionType::E::@getter::it
-          declaringFormalParameter: <testLibrary>::@extensionType::E::@constructor::new::@formalParameter::it
-      constructors
-        declaring isExtensionTypeMember isOriginDeclaration isPrimary new
-          reference: <testLibrary>::@extensionType::E::@constructor::new
-          firstFragment: #F7
-          formalParameters
-            #E0 requiredPositional final hasImplicitType declaring this.it
-              firstFragment: #F8
-              type: int
-              field: <testLibrary>::@extensionType::E::@field::it
-      getters
-        synthetic isExtensionTypeMember isOriginVariable it
-          reference: <testLibrary>::@extensionType::E::@getter::it
-          firstFragment: #F9
-          returnType: int
-          variable: <testLibrary>::@extensionType::E::@field::it
-''');
-  }
-
   test_primaryConstructor_formalParameters_memberWithClassName() async {
     var library = await buildLibrary(r'''
 extension type A(int A) {}
diff --git a/pkg/front_end/lib/src/type_inference/for_in.dart b/pkg/front_end/lib/src/type_inference/for_in.dart
index 86a3a04..ba85f40 100644
--- a/pkg/front_end/lib/src/type_inference/for_in.dart
+++ b/pkg/front_end/lib/src/type_inference/for_in.dart
@@ -71,11 +71,14 @@
     );
 
     variableSet.value = rhs..parent = variableSet;
-    visitor.flowAnalysis.write(
+    visitor.flowAnalysis.storeExpressionInfo(
       variableSet,
-      variableSet.variable,
-      new SharedTypeView(rhsType),
-      null,
+      visitor.flowAnalysis.write(
+        variableSet,
+        variableSet.variable,
+        new SharedTypeView(rhsType),
+        null,
+      ),
     );
     return variableSet;
   }
diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart
index ce3fabd..7eefa4e 100644
--- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart
@@ -1258,7 +1258,10 @@
     BoolLiteral node,
     DartType typeContext,
   ) {
-    flowAnalysis.booleanLiteral(node, node.value);
+    flowAnalysis.storeExpressionInfo(
+      node,
+      flowAnalysis.booleanLiteral(node.value),
+    );
     return new ExpressionInferenceResult(
       coreTypes.boolRawType(Nullability.nonNullable),
       node,
@@ -1458,11 +1461,13 @@
       inferredType = t;
     }
 
-    flowAnalysis.conditional_end(
+    flowAnalysis.storeExpressionInfo(
       node,
-      new SharedTypeView(inferredType),
-      node.otherwise,
-      new SharedTypeView(otherwiseResult.inferredType),
+      flowAnalysis.conditional_end(
+        new SharedTypeView(inferredType),
+        node.otherwise,
+        new SharedTypeView(otherwiseResult.inferredType),
+      ),
     );
     node.staticType = inferredType;
     return new ExpressionInferenceResult(inferredType, node);
@@ -4065,12 +4070,14 @@
       isVoidAllowed: false,
     );
     node.operand = operandResult.expression..parent = node;
-    flowAnalysis.isExpression_end(
+    flowAnalysis.storeExpressionInfo(
       node,
-      node.operand,
-      /*isNot:*/ false,
-      subExpressionType: new SharedTypeView(operandResult.inferredType),
-      checkedType: new SharedTypeView(node.type),
+      flowAnalysis.isExpression_end(
+        node.operand,
+        /*isNot:*/ false,
+        subExpressionType: new SharedTypeView(operandResult.inferredType),
+        checkedType: new SharedTypeView(node.type),
+      ),
     );
     return new ExpressionInferenceResult(
       coreTypes.boolRawType(Nullability.nonNullable),
@@ -4983,10 +4990,12 @@
     );
     Expression right = ensureAssignableResult(boolType, rightResult).expression;
     node.right = right..parent = node;
-    flowAnalysis.logicalBinaryOp_end(
+    flowAnalysis.storeExpressionInfo(
       node,
-      node.right,
-      isAnd: node.operatorEnum == LogicalExpressionOperator.AND,
+      flowAnalysis.logicalBinaryOp_end(
+        node.right,
+        isAnd: node.operatorEnum == LogicalExpressionOperator.AND,
+      ),
     );
     return new ExpressionInferenceResult(boolType, node);
   }
@@ -10516,13 +10525,15 @@
       if (isNot) {
         equals = new Not(equals)..fileOffset = fileOffset;
       }
-      flowAnalysis.equalityOperation_end(
+      flowAnalysis.storeExpressionInfo(
         equals,
-        equalityInfo,
-        new SharedTypeView(leftType),
-        flowAnalysis.equalityOperand_end(rightResult.expression),
-        new SharedTypeView(rightResult.inferredType),
-        notEqual: isNot,
+        flowAnalysis.equalityOperation_end(
+          equalityInfo,
+          new SharedTypeView(leftType),
+          flowAnalysis.equalityOperand_end(rightResult.expression),
+          new SharedTypeView(rightResult.inferredType),
+          notEqual: isNot,
+        ),
       );
       return new ExpressionInferenceResult(
         coreTypes.boolRawType(Nullability.nonNullable),
@@ -10571,13 +10582,15 @@
       equals = new Not(equals)..fileOffset = fileOffset;
     }
 
-    flowAnalysis.equalityOperation_end(
+    flowAnalysis.storeExpressionInfo(
       equals,
-      equalityInfo,
-      new SharedTypeView(leftType),
-      flowAnalysis.equalityOperand_end(right),
-      new SharedTypeView(rightResult.inferredType),
-      notEqual: isNot,
+      flowAnalysis.equalityOperation_end(
+        equalityInfo,
+        new SharedTypeView(leftType),
+        flowAnalysis.equalityOperand_end(right),
+        new SharedTypeView(rightResult.inferredType),
+        notEqual: isNot,
+      ),
     );
     return new ExpressionInferenceResult(
       equalsTarget.isNever
@@ -12136,7 +12149,10 @@
     DartType typeContext,
   ) {
     const NullType nullType = const NullType();
-    flowAnalysis.nullLiteral(node, new SharedTypeView(nullType));
+    flowAnalysis.storeExpressionInfo(
+      node,
+      flowAnalysis.nullLiteral(new SharedTypeView(nullType)),
+    );
     return new ExpressionInferenceResult(nullType, node);
   }
 
@@ -13436,10 +13452,9 @@
     ThisExpression node,
     DartType typeContext,
   ) {
-    flowAnalysis.thisOrSuper(
+    flowAnalysis.storeExpressionInfo(
       node,
-      new SharedTypeView(thisType!),
-      isSuper: false,
+      flowAnalysis.thisOrSuper(new SharedTypeView(thisType!), isSuper: false),
     );
     return new ExpressionInferenceResult(thisType!, node);
   }
diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
index f03ac94..47f4fdc 100644
--- a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
@@ -1967,12 +1967,14 @@
     }
 
     if (isIdenticalCall) {
-      flowAnalysis.equalityOperation_end(
+      flowAnalysis.storeExpressionInfo(
         actualArguments.parent as Expression,
-        argumentsInfo[0].identicalInfo,
-        new SharedTypeView(argumentsInfo[0].actualType),
-        argumentsInfo[1].identicalInfo,
-        new SharedTypeView(argumentsInfo[1].actualType),
+        flowAnalysis.equalityOperation_end(
+          argumentsInfo[0].identicalInfo,
+          new SharedTypeView(argumentsInfo[0].actualType),
+          argumentsInfo[1].identicalInfo,
+          new SharedTypeView(argumentsInfo[1].actualType),
+        ),
       );
     }
 
@@ -4275,18 +4277,21 @@
     node ??= new VariableGet(variable.astVariable)..fileOffset = nameOffset;
     DartType? promotedType;
     DartType declaredOrInferredType = variable.lateType ?? variable.type;
+    ExpressionInfo? expressionInfo;
     if (isExtensionThis(variable.astVariable)) {
-      flowAnalysis.thisOrSuper(
-        node,
+      expressionInfo = flowAnalysis.thisOrSuper(
         new SharedTypeView(variable.type),
         isSuper: true,
       );
     } else if (!variable.isLocalFunction) {
       // Don't promote local functions.
-      promotedType = flowAnalysis
-          .variableRead(node, variable.astVariable)
-          ?.unwrapTypeView();
+      SharedTypeView? wrappedPromotedType;
+      (wrappedPromotedType, expressionInfo) = flowAnalysis.variableRead(
+        variable.astVariable,
+      );
+      promotedType = wrappedPromotedType?.unwrapTypeView();
     }
+    flowAnalysis.storeExpressionInfo(node, expressionInfo);
     node.promotedType = promotedType;
     DartType resultType = promotedType ?? declaredOrInferredType;
     Expression resultExpression;
@@ -4419,11 +4424,14 @@
     Expression rhs = rhsResult.expression;
     node ??= new VariableSet(variable.astVariable, rhs)
       ..fileOffset = nameOffset;
-    flowAnalysis.write(
+    flowAnalysis.storeExpressionInfo(
       node,
-      variable.astVariable,
-      new SharedTypeView(rhsResult.inferredType),
-      rhsResult.expression,
+      flowAnalysis.write(
+        node,
+        variable.astVariable,
+        new SharedTypeView(rhsResult.inferredType),
+        rhsResult.expression,
+      ),
     );
     DartType resultType = rhsResult.inferredType;
     Expression resultExpression;
diff --git a/tests/language/extension_type/no_inheritance_inference_test.dart b/tests/language/extension_type/no_inheritance_inference_test.dart
new file mode 100644
index 0000000..0fce2cf
--- /dev/null
+++ b/tests/language/extension_type/no_inheritance_inference_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2026, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/static_type_helper.dart';
+
+class A {
+  A get x => this;
+  set x(A _) {}
+  A method(A value) => value;
+}
+
+const Object? d = _D();
+
+class _D {
+  const _D();
+  // Can only be called if receiver has type `_D` or `dynamic`,
+  // and nothing has type `_D`.
+  void expectDynamicType() {}
+}
+
+extension type E(A _) {
+  A get x2 => _;
+  set x2(A _) {}
+  A method2(A value) => value;
+}
+
+// Extension type declarations with missing types *do not* inherit from
+// superinterface members.
+extension type SE(A _) implements A, E {
+  get x => d;
+  set x(_) {}
+  method(_) {}
+  get x2 => d;
+  set x2(_) {}
+  method2(_) {}
+}
+
+void main() {
+  var se = SE(A());
+  se.x.expectDynamicType();
+  se.x = expr(d)..expectDynamicType();
+  se.method.expectStaticType<Exactly<dynamic Function(dynamic)>>();
+  se.x2.expectDynamicType();
+  se.x2 = expr(d)..expectDynamicType();
+  se.method2.expectStaticType<Exactly<dynamic Function(dynamic)>>();
+}
+
+/// Expression with type [T].
+///
+/// Inferred to have same type as context type if no type parameter provided.
+T expr<T>([Object? value]) => value as T;
diff --git a/tools/VERSION b/tools/VERSION
index b8f3a2b..aaaf7d7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 3
 MINOR 12
 PATCH 0
-PRERELEASE 59
+PRERELEASE 60
 PRERELEASE_PATCH 0