Simplify handling of variable expressions in shared analysis tests.

When using the "mini-ast" pseudo-language to write unit tests for the
flow analysis and type analysis logic in the `_fe_analyzer_shared`
package, it is no longer necessary to use `.expr` to turn a `Var` into
an `Expression`; this now happens automatically. The way this works
under the hood is that the `Var` and `Expression` classes implement
the `ProtoExpression` interface; constructs that expect expressions
are declared with input parameters of type `ProtoExpression`, and they
automatically convert to `Expression`s when necessary.

Change-Id: I85c493145c3fc41a5296c1807cd63fe1401672db
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315247
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
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 b449161..7f43a6a 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
@@ -135,20 +135,26 @@
   }
 }
 
-extension ExpressionExtensionForFlowAnalysisTesting on Expression {
+extension ExpressionExtensionForFlowAnalysisTesting on ProtoExpression {
   /// Creates an [Expression] that, when analyzed, will behave the same as
   /// `this`, but after visiting it, will cause [callback] to be passed the
   /// [ExpressionInfo] associated with it.  If the expression has no flow
   /// analysis information associated with it, `null` will be passed to
   /// [callback].
-  Expression getExpressionInfo(void Function(ExpressionInfo<Type>?) callback) =>
-      new _GetExpressionInfo(this, callback, location: computeLocation());
+  Expression getExpressionInfo(void Function(ExpressionInfo<Type>?) callback) {
+    var location = computeLocation();
+    return new _GetExpressionInfo(asExpression(location: location), callback,
+        location: location);
+  }
 
   /// Creates an [Expression] that, when analyzed, will behave the same as
   /// `this`, but after visiting it, will cause [callback] to be passed the
   /// non-promotion info associated with it.  If the expression has no
   /// non-promotion info, an empty map will be passed to [callback].
   Expression whyNotPromoted(
-          void Function(Map<Type, NonPromotionReason>) callback) =>
-      new _WhyNotPromoted(this, callback, location: computeLocation());
+      void Function(Map<Type, NonPromotionReason>) callback) {
+    var location = computeLocation();
+    return new _WhyNotPromoted(asExpression(location: location), callback,
+        location: location);
+  }
 }
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 ab8ae5c..63040a5 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
@@ -24,7 +24,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         getSsaNodes((nodes) => expect(nodes[x], same(ssaBeforePromotion))),
       ]);
@@ -52,8 +52,8 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        assert_(x.expr.eq(nullLiteral),
-            second(checkPromoted(x, 'int'), expr('String'))),
+        assert_(
+            x.eq(nullLiteral), second(checkPromoted(x, 'int'), expr('String'))),
       ]);
     });
 
@@ -65,15 +65,15 @@
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
         declare(z, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
-        z.expr.as_('int'),
+        x.as_('int'),
+        z.as_('int'),
         assert_(second(
                 listLiteral(elementType: 'dynamic', [
                   x.write(expr('int?')),
                   z.write(expr('int?')),
                 ]),
                 expr('bool'))
-            .and(x.expr.notEq(nullLiteral).and(y.expr.notEq(nullLiteral)))),
+            .and(x.notEq(nullLiteral).and(y.notEq(nullLiteral)))),
         // x should be promoted because it was promoted before the assert, and
         // it is re-promoted within the assert (if it passes)
         checkPromoted(x, 'int'),
@@ -90,7 +90,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.notEq(nullLiteral).conditional(
+        x.notEq(nullLiteral).conditional(
             second(checkPromoted(x, 'int'), expr('int')),
             second(checkNotPromoted(x), expr('int'))),
         checkNotPromoted(x),
@@ -101,8 +101,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.eq(nullLiteral).conditional(
-            second(checkNotPromoted(x), expr('Null')),
+        x.eq(nullLiteral).conditional(second(checkNotPromoted(x), expr('Null')),
             second(checkPromoted(x, 'int'), expr('Null'))),
         checkNotPromoted(x),
       ]);
@@ -120,14 +119,14 @@
         expr('bool').conditional(
             second(
                 listLiteral(elementType: 'dynamic', [
-                  x.expr.as_('int'),
-                  y.expr.as_('int'),
+                  x.as_('int'),
+                  y.as_('int'),
                 ]),
                 expr('Null')),
             second(
                 listLiteral(elementType: 'dynamic', [
-                  x.expr.as_('int'),
-                  z.expr.as_('int'),
+                  x.as_('int'),
+                  z.as_('int'),
                 ]),
                 expr('Null'))),
         checkPromoted(x, 'int'),
@@ -150,8 +149,8 @@
         declare(z, type: 'int?', initializer: expr('int?')),
         if_(
             expr('bool').conditional(
-                x.expr.notEq(nullLiteral).and(y.expr.notEq(nullLiteral)),
-                x.expr.notEq(nullLiteral).and(z.expr.notEq(nullLiteral))),
+                x.notEq(nullLiteral).and(y.notEq(nullLiteral)),
+                x.notEq(nullLiteral).and(z.notEq(nullLiteral))),
             [
               checkPromoted(x, 'int'),
               checkNotPromoted(y),
@@ -174,9 +173,8 @@
         declare(y, type: 'int?', initializer: expr('int?')),
         declare(z, type: 'int?', initializer: expr('int?')),
         if_(
-            expr('bool').conditional(
-                x.expr.eq(nullLiteral).or(y.expr.eq(nullLiteral)),
-                x.expr.eq(nullLiteral).or(z.expr.eq(nullLiteral))),
+            expr('bool').conditional(x.eq(nullLiteral).or(y.eq(nullLiteral)),
+                x.eq(nullLiteral).or(z.eq(nullLiteral))),
             [],
             [
               checkPromoted(x, 'int'),
@@ -202,7 +200,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
-        if_(x.expr.notEq(nullLiteral), [
+        if_(x.notEq(nullLiteral), [
           checkReachable(true),
           checkPromoted(x, 'int'),
           getSsaNodes((nodes) => expect(nodes[x], same(ssaBeforePromotion))),
@@ -218,7 +216,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int', initializer: expr('int')),
-        if_(x.expr.notEq(nullLiteral), [
+        if_(x.notEq(nullLiteral), [
           checkReachable(true),
           checkNotPromoted(x),
         ], [
@@ -252,7 +250,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.notEq(expr('Null')), [
+        if_(x.notEq(expr('Null')), [
           checkNotPromoted(x),
         ], [
           checkNotPromoted(x),
@@ -266,7 +264,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
-        if_(x.expr.eq(nullLiteral), [
+        if_(x.eq(nullLiteral), [
           checkReachable(true),
           checkNotPromoted(x),
           getSsaNodes((nodes) => expect(nodes[x], same(ssaBeforePromotion))),
@@ -282,7 +280,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int', initializer: expr('int')),
-        if_(x.expr.eq(nullLiteral), [
+        if_(x.eq(nullLiteral), [
           checkReachable(true),
           checkNotPromoted(x),
         ], [
@@ -298,7 +296,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
-        if_(nullLiteral.notEq(x.expr), [
+        if_(nullLiteral.notEq(x), [
           checkPromoted(x, 'int'),
           getSsaNodes((nodes) => expect(nodes[x], same(ssaBeforePromotion))),
         ], [
@@ -312,7 +310,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(expr('Null').notEq(x.expr), [
+        if_(expr('Null').notEq(x), [
           checkNotPromoted(x),
         ], [
           checkNotPromoted(x),
@@ -326,7 +324,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
-        if_(nullLiteral.eq(x.expr), [
+        if_(nullLiteral.eq(x), [
           checkNotPromoted(x),
           getSsaNodes((nodes) => expect(nodes[x], same(ssaBeforePromotion))),
         ], [
@@ -400,13 +398,13 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.notEq(nullLiteral), [
+        if_(x.notEq(nullLiteral), [
           checkPromoted(x, 'int'),
         ]),
         localFunction([
           x.write(expr('int?')),
         ]),
-        if_(x.expr.notEq(nullLiteral), [
+        if_(x.notEq(nullLiteral), [
           checkNotPromoted(x),
         ]),
       ]);
@@ -437,7 +435,7 @@
       late SsaNode<Type> ssaBeforeLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         getSsaNodes((nodes) => ssaBeforeLoop = nodes[x]!),
         do_([
@@ -453,7 +451,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         do_([
-          x.expr.as_('int'),
+          x.as_('int'),
           // The promotion should have no effect, because the second time
           // through the loop, x has been write-captured.
           checkNotPromoted(x),
@@ -470,7 +468,7 @@
         declare(x, type: 'int?', initializer: expr('int?')),
         do_(
             [
-              if_(x.expr.notEq(nullLiteral), [
+              if_(x.notEq(nullLiteral), [
                 continue_(),
               ]),
               return_(),
@@ -490,10 +488,8 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        do_(
-            [],
-            second(checkNotPromoted(x), expr('bool'))
-                .or(x.expr.eq(nullLiteral))),
+        do_([],
+            second(checkNotPromoted(x), expr('bool')).or(x.eq(nullLiteral))),
         checkPromoted(x, 'int'),
       ]);
     });
@@ -508,7 +504,7 @@
       h.run([
         declare(x, type: 'C', initializer: expr('C')),
         checkAssigned(x, true),
-        if_(x.expr.property('y').notEq(nullLiteral), [
+        if_(x.property('y').notEq(nullLiteral), [
           checkAssigned(x, true),
         ], [
           checkAssigned(x, true),
@@ -536,8 +532,8 @@
         var x = Var('x');
         h.run([
           declare(x, type: 'C', initializer: expr('C')),
-          if_(x.expr.property('f').is_('Null'), [
-            if_(x.expr.property('f').eq(nullLiteral), [
+          if_(x.property('f').is_('Null'), [
+            if_(x.property('f').eq(nullLiteral), [
               checkReachable(true),
             ], [
               checkReachable(true),
@@ -604,7 +600,7 @@
       late SsaNode<Type> ssaBeforeLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         getSsaNodes((nodes) => ssaBeforeLoop = nodes[x]!),
         for_(
@@ -627,13 +623,13 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         for_(
             null,
             second(
                 listLiteral(elementType: 'dynamic', [
-                  x.expr.as_('int'),
+                  x.as_('int'),
                   checkNotPromoted(x),
                   localFunction([
                     x.write(expr('int?')),
@@ -656,7 +652,7 @@
       var x = Var('x');
       h.run([
         for_(declare(x, type: 'int?', initializer: expr('int?')),
-            x.expr.notEq(nullLiteral), null, [
+            x.notEq(nullLiteral), null, [
           checkPromoted(x, 'int'),
         ]),
       ]);
@@ -668,7 +664,7 @@
       var x = Var('x');
       h.run([
         for_(declare(x, type: 'int?', initializer: expr('int?')),
-            x.expr.notEq(nullLiteral), null, [],
+            x.notEq(nullLiteral), null, [],
             forCollection: true),
       ]);
     });
@@ -697,12 +693,12 @@
                 expr('Null')),
             [
               if_(expr('bool'), [
-                x.expr.as_('int'),
-                y.expr.as_('int'),
+                x.as_('int'),
+                y.as_('int'),
                 continue_(),
               ]),
-              x.expr.as_('int'),
-              z.expr.as_('int'),
+              x.as_('int'),
+              z.as_('int'),
             ]),
       ]);
     });
@@ -719,10 +715,10 @@
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
         declare(z, type: 'int?', initializer: expr('int?')),
-        for_(null, x.expr.eq(nullLiteral).or(z.expr.eq(nullLiteral)), null, [
+        for_(null, x.eq(nullLiteral).or(z.eq(nullLiteral)), null, [
           if_(expr('bool'), [
-            x.expr.as_('int'),
-            y.expr.as_('int'),
+            x.as_('int'),
+            y.as_('int'),
             break_(),
           ]),
         ]),
@@ -771,7 +767,7 @@
         for_(null, expr('bool'), null, [
           x.write(expr('int?')),
           if_(expr('bool'), [break_()]),
-          if_(x.expr.is_('int'), []),
+          if_(x.is_('int'), []),
           getSsaNodes((nodes) {
             xSsaInsideLoop = nodes[x]!;
             ySsaInsideLoop = nodes[y]!;
@@ -792,7 +788,7 @@
       late SsaNode<Type> ssaBeforeLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         getSsaNodes((nodes) => ssaBeforeLoop = nodes[x]!),
         forEachWithNonVariable(expr('List<int?>'), [
@@ -807,10 +803,10 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         forEachWithNonVariable(expr('List<int?>'), [
-          x.expr.as_('int'),
+          x.as_('int'),
           checkNotPromoted(x),
           localFunction([
             x.write(expr('int?')),
@@ -838,7 +834,7 @@
         checkAssigned(x, false),
         forEachWithVariableSet(x, expr('List<int?>'), [
           checkAssigned(x, true),
-          if_(x.expr.notEq(nullLiteral), [checkPromoted(x, 'int')]),
+          if_(x.notEq(nullLiteral), [checkPromoted(x, 'int')]),
         ]),
         checkAssigned(x, false),
       ]);
@@ -867,7 +863,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         forEachWithNonVariable(expr('List<int?>'), [
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'),
         ]),
         checkNotPromoted(x),
@@ -881,8 +877,8 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
-        y.expr.as_('int'),
+        x.as_('int'),
+        y.as_('int'),
         checkPromoted(x, 'int'),
         checkPromoted(y, 'int'),
         getSsaNodes((nodes) {
@@ -896,7 +892,7 @@
             expect(nodes[x], isNull);
             expect(nodes[y], isNotNull);
           }),
-          x.write(expr('int?')), x.expr.as_('int'),
+          x.write(expr('int?')), x.as_('int'),
         ]),
         // x is unpromoted after the local function too
         checkNotPromoted(x), checkPromoted(y, 'int'),
@@ -914,7 +910,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'), y.expr.as_('int'),
+        x.as_('int'), y.as_('int'),
         checkPromoted(x, 'int'), checkPromoted(y, 'int'),
         localFunction([
           // x is unpromoted within the local function, because the write
@@ -922,7 +918,7 @@
           checkNotPromoted(x), checkPromoted(y, 'int'),
           // And any effort to promote x fails, because there is no way of
           // knowing when the captured write might occur.
-          x.expr.as_('int'),
+          x.as_('int'),
           checkNotPromoted(x), checkPromoted(y, 'int'),
         ]),
         // x is still promoted after the local function, though, because the
@@ -946,7 +942,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'), y.expr.as_('int'),
+        x.as_('int'), y.as_('int'),
         checkPromoted(x, 'int'),
         getSsaNodes((nodes) => ssaBeforeFunction = nodes[x]!),
         checkPromoted(y, 'int'),
@@ -957,7 +953,7 @@
           getSsaNodes((nodes) => expect(nodes[x], isNot(ssaBeforeFunction))),
           checkPromoted(y, 'int'),
           // But it can be re-promoted because the write isn't captured.
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'), checkPromoted(y, 'int'),
         ]),
         // x is still promoted after the local function, though, because the
@@ -978,8 +974,8 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?'), isLate: true),
-        x.expr.as_('int'),
-        y.expr.as_('int'),
+        x.as_('int'),
+        y.as_('int'),
         checkPromoted(x, 'int'),
         checkPromoted(y, 'int'),
         localFunction([
@@ -1003,7 +999,7 @@
         // x is declared after the local function, so the local function
         // cannot possibly write to x.
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'), x.write(expr('Null')),
       ]);
     });
@@ -1015,11 +1011,11 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
-        y.expr.as_('int'),
+        y.as_('int'),
         getSsaNodes((nodes) => expect(nodes[x], isNotNull)),
         localFunction([
           getSsaNodes((nodes) => expect(nodes[x], isNot(nodes[y]))),
-          x.expr.as_('int'),
+          x.as_('int'),
           // Promotion should not occur, because x might be write-captured by
           // the time this code is reached.
           checkNotPromoted(x),
@@ -1139,7 +1135,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr
+        x
             .ifNull(second(
                 listLiteral(elementType: 'dynamic', [
                   checkReachable(true),
@@ -1158,11 +1154,11 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr
+        x
             .ifNull(second(
                 listLiteral(elementType: 'dynamic', [
                   checkReachable(true),
-                  x.expr.as_('int'),
+                  x.as_('int'),
                   checkPromoted(x, 'int'),
                 ]),
                 expr('int?')))
@@ -1181,7 +1177,7 @@
             .ifNull(second(
                 listLiteral(elementType: 'dynamic', [
                   checkReachable(true),
-                  x.expr.as_('int'),
+                  x.as_('int'),
                   checkPromoted(x, 'int'),
                 ]),
                 expr('int?')))
@@ -1235,7 +1231,7 @@
         declare(x, type: 'int?', initializer: expr('int?')),
         return_(),
         checkReachable(false),
-        if_(x.expr.eq(nullLiteral), [
+        if_(x.eq(nullLiteral), [
           return_(),
         ]),
         checkReachable(false),
@@ -1247,7 +1243,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.eq(nullLiteral), [
+        if_(x.eq(nullLiteral), [
           return_(),
         ]),
         checkPromoted(x, 'int'),
@@ -1267,15 +1263,15 @@
         declare(x, type: 'bool', initializer: expr('bool')),
         declare(y, type: 'bool', initializer: expr('bool')),
         declare(z, type: 'bool', initializer: expr('bool')),
-        x.write(w.expr.is_('int')),
+        x.write(w.is_('int')),
         getSsaNodes((nodes) {
           xSsaNodeBeforeIf = nodes[x]!;
           expect(xSsaNodeBeforeIf.expressionInfo, isNotNull);
         }),
         if_(expr('bool'), [
-          y.write(w.expr.is_('String')),
+          y.write(w.is_('String')),
         ], [
-          z.write(w.expr.is_('bool')),
+          z.write(w.is_('bool')),
         ]),
         getSsaNodes((nodes) {
           expect(nodes[x], same(xSsaNodeBeforeIf));
@@ -1415,7 +1411,7 @@
       var y = Var('y');
       h.run([
         declare(y, type: 'int?', initializer: expr('int?')),
-        declare(x, type: 'Object', initializer: y.expr.eq(nullLiteral)),
+        declare(x, type: 'Object', initializer: y.eq(nullLiteral)),
         getSsaNodes((nodes) {
           var info = nodes[x]!.expressionInfo!;
           var key = h.promotionKeyStore.keyForVariable(y);
@@ -1433,7 +1429,7 @@
       h.run([
         declare(y, type: 'int?', initializer: expr('int?')),
         declare(x,
-            isLate: true, type: 'Object', initializer: y.expr.eq(nullLiteral)),
+            isLate: true, type: 'Object', initializer: y.eq(nullLiteral)),
         getSsaNodes((nodes) {
           expect(nodes[x]!.expressionInfo, isNull);
         }),
@@ -1448,8 +1444,7 @@
       var y = Var('y');
       h.run([
         declare(y, type: 'int?', initializer: expr('int?')),
-        declare(x,
-            initializer: y.expr.eq(nullLiteral), expectInferredType: 'bool'),
+        declare(x, initializer: y.eq(nullLiteral), expectInferredType: 'bool'),
         getSsaNodes((nodes) {
           expect(nodes[x]!.expressionInfo, isNull);
         }),
@@ -1464,8 +1459,7 @@
       var y = Var('y');
       h.run([
         declare(y, type: 'int?', initializer: expr('int?')),
-        declare(x,
-            initializer: y.expr.eq(nullLiteral), expectInferredType: 'bool'),
+        declare(x, initializer: y.eq(nullLiteral), expectInferredType: 'bool'),
         getSsaNodes((nodes) {
           expect(nodes[x]!.expressionInfo, isNotNull);
         }),
@@ -1480,7 +1474,7 @@
       var y = Var('y');
       h.run([
         declare(y, type: 'int?', initializer: expr('int?')),
-        declare(x, type: 'Object', initializer: y.expr.eq(nullLiteral)),
+        declare(x, type: 'Object', initializer: y.eq(nullLiteral)),
         getSsaNodes((nodes) {
           expect(nodes[x]!.expressionInfo, isNotNull);
         }),
@@ -1500,7 +1494,7 @@
             type: 'Object',
             // `y == null` is a trivial expression because y has been write
             // captured.
-            initializer: y.expr
+            initializer: y
                 .eq(nullLiteral)
                 .getExpressionInfo((info) => expect(info, isNotNull))),
         getSsaNodes((nodes) {
@@ -1517,7 +1511,7 @@
       h.run([
         declare(x, type: declaredType, initializer: expr(declaredType)),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
-        if_(x.expr.is_(tryPromoteType, isInverted: inverted), [
+        if_(x.is_(tryPromoteType, isInverted: inverted), [
           checkReachable(true),
           checkPromoted(x, expectedPromotedTypeThen),
           getSsaNodes((nodes) => expect(nodes[x], same(ssaBeforePromotion))),
@@ -1579,13 +1573,13 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.is_('int'), [
+        if_(x.is_('int'), [
           checkPromoted(x, 'int'),
         ]),
         localFunction([
           x.write(expr('int?')),
         ]),
-        if_(x.expr.is_('int'), [
+        if_(x.is_('int'), [
           checkNotPromoted(x),
         ]),
       ]);
@@ -1608,7 +1602,7 @@
         var x = Var('x');
         h.run([
           declare(x, type: 'C', initializer: expr('C')),
-          if_(x.expr.property('f').is_('Never'), [
+          if_(x.property('f').is_('Never'), [
             checkReachable(false),
           ], [
             checkReachable(true),
@@ -1667,7 +1661,7 @@
       var l = Label('l');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.isNot('int'), [
+        if_(x.isNot('int'), [
           l.thenStmt(return_()),
         ]),
         checkPromoted(x, 'int'),
@@ -1679,7 +1673,7 @@
       var l = Label('l');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.isNot('int'), [
+        if_(x.isNot('int'), [
           l.thenStmt(block([
             if_(expr('bool'), [
               break_(l),
@@ -1695,9 +1689,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr
-            .notEq(nullLiteral)
-            .and(second(checkPromoted(x, 'int'), expr('bool'))),
+        x.notEq(nullLiteral).and(second(checkPromoted(x, 'int'), expr('bool'))),
       ]);
     });
 
@@ -1705,7 +1697,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(expr('bool').and(x.expr.notEq(nullLiteral)), [
+        if_(expr('bool').and(x.notEq(nullLiteral)), [
           checkPromoted(x, 'int'),
         ]),
       ]);
@@ -1716,7 +1708,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(expr('bool').or(x.expr.eq(nullLiteral)), [], [
+        if_(expr('bool').or(x.eq(nullLiteral)), [], [
           checkPromoted(x, 'int'),
         ]),
       ]);
@@ -1726,9 +1718,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr
-            .eq(nullLiteral)
-            .or(second(checkPromoted(x, 'int'), expr('bool'))),
+        x.eq(nullLiteral).or(second(checkPromoted(x, 'int'), expr('bool'))),
       ]);
     });
 
@@ -1742,7 +1732,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.notEq(nullLiteral).and(y.expr.notEq(nullLiteral)), [
+        if_(x.notEq(nullLiteral).and(y.notEq(nullLiteral)), [
           checkPromoted(x, 'int'),
           checkPromoted(y, 'int'),
         ]),
@@ -1759,7 +1749,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.eq(nullLiteral).or(y.expr.eq(nullLiteral)), [], [
+        if_(x.eq(nullLiteral).or(y.eq(nullLiteral)), [], [
           checkPromoted(x, 'int'),
           checkPromoted(y, 'int'),
         ]),
@@ -1770,7 +1760,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.eq(nullLiteral).not, [
+        if_(x.eq(nullLiteral).not, [
           checkPromoted(x, 'int'),
         ], [
           checkNotPromoted(x),
@@ -1792,7 +1782,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
-        x.expr.nonNullAssert,
+        x.nonNullAssert,
         checkPromoted(x, 'int'),
         getSsaNodes((nodes) => expect(nodes[x], same(ssaBeforePromotion))),
       ]);
@@ -1814,7 +1804,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforePromotion = nodes[x]!),
-        x.expr.nullAwareAccess(second(
+        x.nullAwareAccess(second(
             listLiteral(elementType: 'dynamic', [
               checkReachable(true),
               checkPromoted(x, 'int'),
@@ -1831,7 +1821,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.nullAwareAccess(
+        x.nullAwareAccess(
             second(
                 listLiteral(elementType: 'dynamic', [
                   checkReachable(true),
@@ -1846,7 +1836,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         expr('int').nullAwareAccess(second(
                 listLiteral(elementType: 'dynamic', [
                   checkReachable(true),
@@ -1873,7 +1863,7 @@
         expr('int').nullAwareAccess(second(
             listLiteral(elementType: 'dynamic', [
               checkReachable(true),
-              x.expr.as_('int'),
+              x.as_('int'),
               checkPromoted(x, 'int'),
             ]),
             expr('Null'))),
@@ -1887,11 +1877,9 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(
-            x.expr.parenthesized.notEq(nullLiteral.parenthesized).parenthesized,
-            [
-              checkPromoted(x, 'int'),
-            ]),
+        if_(x.parenthesized.notEq(nullLiteral.parenthesized).parenthesized, [
+          checkPromoted(x, 'int'),
+        ]),
       ]);
     });
 
@@ -1927,7 +1915,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         ifCase(
-          x.expr.notEq(nullLiteral),
+          x.notEq(nullLiteral),
           intLiteral(0).pattern,
           [
             checkNotPromoted(x),
@@ -1941,10 +1929,10 @@
       h.run([
         declare(x, type: 'num?', initializer: expr('num?')),
         checkNotPromoted(x),
-        x.expr.as_('num'),
+        x.as_('num'),
         checkPromoted(x, 'num'),
         // Check that it's a type of interest by promoting and de-promoting.
-        if_(x.expr.is_('int'), [
+        if_(x.is_('int'), [
           checkPromoted(x, 'int'),
           x.write(expr('num')),
           checkPromoted(x, 'num'),
@@ -1957,7 +1945,7 @@
       h.run([
         declare(x, type: 'num?', initializer: expr('num?')),
         checkNotPromoted(x),
-        x.expr.as_('String'),
+        x.as_('String'),
         checkNotPromoted(x),
       ]);
     });
@@ -1970,7 +1958,7 @@
         localFunction([
           x.write(expr('num')),
         ]),
-        x.expr.as_('num'),
+        x.as_('num'),
         checkNotPromoted(x),
       ]);
     });
@@ -2057,7 +2045,7 @@
       var x = Var('x');
       h.run([
         switch_(expr('num'), [
-          x.pattern().when(x.expr.is_('int')).then([
+          x.pattern().when(x.is_('int')).then([
             checkPromoted(x, 'int'),
           ]),
         ]),
@@ -2070,7 +2058,7 @@
         switchExpr(expr('num'), [
           x
               .pattern()
-              .when(x.expr.is_('int'))
+              .when(x.is_('int'))
               .thenExpr(second(checkPromoted(x, 'int'), expr('String'))),
         ]),
       ]);
@@ -2080,7 +2068,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         switch_(expr('int'), [
           intLiteral(0).pattern.then([
             checkPromoted(x, 'int'),
@@ -2100,7 +2088,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         switch_(expr('int'), [
           intLiteral(0).pattern.then([
             checkPromoted(x, 'int'),
@@ -2116,7 +2104,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         switch_(
           expr('int'),
           [
@@ -2137,7 +2125,7 @@
       late SsaNode<Type> ssaBeforeSwitch;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         switch_(
           expr('int').thenStmt(block([
             checkPromoted(x, 'int'),
@@ -2161,14 +2149,14 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         switch_(
           expr('int'),
           [
             switchStatementMember([
               intLiteral(0).pattern,
             ], [
-              x.expr.as_('int'),
+              x.as_('int'),
               checkNotPromoted(x),
               localFunction([
                 x.write(expr('int?')),
@@ -2188,11 +2176,11 @@
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
         declare(z, type: 'int?', initializer: expr('int?')),
-        y.expr.as_('int'),
-        z.expr.as_('int'),
+        y.as_('int'),
+        z.as_('int'),
         switch_(expr('int'), [
           intLiteral(0).pattern.then([
-            x.expr.as_('int'),
+            x.as_('int'),
             y.write(expr('int?')),
             break_(),
           ]),
@@ -2213,19 +2201,19 @@
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
         declare(z, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
-        y.expr.as_('int'),
-        z.expr.as_('int'),
+        x.as_('int'),
+        y.as_('int'),
+        z.as_('int'),
         switch_(expr('int'), [
           intLiteral(0).pattern.then([
-            w.expr.as_('int'),
-            y.expr.as_('int'),
+            w.as_('int'),
+            y.as_('int'),
             x.write(expr('int?')),
             break_(),
           ]),
           default_.then([
-            w.expr.as_('int'),
-            x.expr.as_('int'),
+            w.as_('int'),
+            x.as_('int'),
             y.write(expr('int?')),
             break_(),
           ]),
@@ -2243,7 +2231,7 @@
         declare(x, type: 'int?', initializer: expr('int?')),
         switch_(expr('int'), [
           intLiteral(0).pattern.then([
-            x.expr.as_('int'),
+            x.as_('int'),
             break_(),
           ]),
           default_.then([]),
@@ -2265,8 +2253,8 @@
           expr('num'),
           [
             switchStatementMember([
-              x1.pattern().when(x1.expr.is_('int').and(y.expr.is_('int'))),
-              x2.pattern().when(y.expr.is_('int').and(z.expr.is_('int'))),
+              x1.pattern().when(x1.is_('int').and(y.is_('int'))),
+              x2.pattern().when(y.is_('int').and(z.is_('int'))),
             ], [
               checkNotPromoted(x2),
               checkPromoted(y, 'int'),
@@ -2283,9 +2271,9 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
-        y.expr.as_('int'),
+        y.as_('int'),
         try_([
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'),
           checkPromoted(y, 'int'),
         ]).catch_(body: [
@@ -2301,11 +2289,11 @@
       late SsaNode<Type> ssaAfterTry;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         try_([
           x.write(expr('int?')),
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'),
           getSsaNodes((nodes) => ssaAfterTry = nodes[x]!),
         ]).catch_(body: [
@@ -2323,7 +2311,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         try_([
           localFunction([
@@ -2331,7 +2319,7 @@
           ]),
           return_(),
         ]).catch_(body: [
-          x.expr.as_('int'),
+          x.as_('int'),
           checkNotPromoted(x),
         ]),
       ]);
@@ -2343,7 +2331,7 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         try_([]).catch_(body: [
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'),
         ]).catch_(body: [
           checkNotPromoted(x),
@@ -2372,11 +2360,11 @@
         declare(y, type: 'int?', initializer: expr('int?')),
         declare(z, type: 'int?', initializer: expr('int?')),
         try_([
-          x.expr.as_('int'),
-          y.expr.as_('int'),
+          x.as_('int'),
+          y.as_('int'),
         ]).catch_(body: [
-          x.expr.as_('int'),
-          z.expr.as_('int'),
+          x.as_('int'),
+          z.as_('int'),
         ]),
         // Only x should be promoted, because it's the only variable
         // promoted in both the try body and the catch handler.
@@ -2395,11 +2383,11 @@
         try_([
           return_(),
         ]).catch_(body: [
-          x.expr.as_('int'),
-          y.expr.as_('int'),
+          x.as_('int'),
+          y.as_('int'),
         ]).catch_(body: [
-          x.expr.as_('int'),
-          z.expr.as_('int'),
+          x.as_('int'),
+          z.as_('int'),
         ]),
         // Only x should be promoted, because it's the only variable promoted
         // in both catch handlers.
@@ -2413,9 +2401,9 @@
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
-        y.expr.as_('int'),
+        y.as_('int'),
         try_([
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'),
           checkPromoted(y, 'int'),
         ]).finally_([
@@ -2433,12 +2421,12 @@
       late SsaNode<Type> ssaAfterTry;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         try_([
           getSsaNodes((nodes) => ssaAtStartOfTry = nodes[x]!),
           x.write(expr('int?')),
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'),
           getSsaNodes((nodes) => ssaAfterTry = nodes[x]!),
         ]).finally_([
@@ -2469,7 +2457,7 @@
           ]),
           return_(),
         ]).finally_([
-          x.expr.as_('int'),
+          x.as_('int'),
           checkNotPromoted(x),
         ]),
       ]);
@@ -2482,11 +2470,11 @@
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
         try_([
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'),
         ]).finally_([
           checkNotPromoted(x),
-          y.expr.as_('int'),
+          y.as_('int'),
           checkPromoted(y, 'int'),
         ]),
         // Both x and y should now be promoted.
@@ -2505,13 +2493,13 @@
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
         try_([
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'),
         ]).finally_([
           checkNotPromoted(x),
           x.write(expr('int?')),
           y.write(expr('int?')),
-          y.expr.as_('int'),
+          y.as_('int'),
           checkPromoted(y, 'int'),
           getSsaNodes((nodes) {
             xSsaAtEndOfFinally = nodes[x]!;
@@ -2641,7 +2629,7 @@
               x.write(expr('int?')),
             ]),
           ]).finally_([]),
-          if_(x.expr.notEq(nullLiteral), [
+          if_(x.notEq(nullLiteral), [
             checkNotPromoted(x),
           ]),
         ]);
@@ -2658,7 +2646,7 @@
               x.write(expr('int?')),
             ]),
           ]),
-          if_(x.expr.notEq(nullLiteral), [
+          if_(x.notEq(nullLiteral), [
             checkNotPromoted(x),
           ]),
         ]);
@@ -2671,7 +2659,7 @@
         h.run([
           declare(x, type: 'int?', initializer: expr('int?')),
           try_([
-            if_(x.expr.eq(nullLiteral), [
+            if_(x.eq(nullLiteral), [
               return_(),
             ]),
             checkPromoted(x, 'int'),
@@ -2683,7 +2671,7 @@
           // The capture in the `finally` cancels old promotions and prevents
           // future promotions.
           checkNotPromoted(x),
-          if_(x.expr.notEq(nullLiteral), [
+          if_(x.notEq(nullLiteral), [
             checkNotPromoted(x),
           ]),
         ]);
@@ -2696,12 +2684,12 @@
         h.run([
           declare(x, type: 'Object', initializer: expr('Object')),
           try_([
-            if_(x.expr.is_('num', isInverted: true), [
+            if_(x.is_('num', isInverted: true), [
               return_(),
             ]),
             checkPromoted(x, 'num'),
           ]).finally_([
-            if_(x.expr.is_('int', isInverted: true), [
+            if_(x.is_('int', isInverted: true), [
               return_(),
             ]),
           ]),
@@ -2719,13 +2707,13 @@
         h.run([
           declare(x, type: 'Object', initializer: expr('Object')),
           try_([
-            if_(x.expr.is_('String', isInverted: true), [
+            if_(x.is_('String', isInverted: true), [
               return_(),
             ]),
             checkPromoted(x, 'String'),
           ]).finally_([
             x.write(expr('Object')),
-            if_(x.expr.is_('int', isInverted: true), [
+            if_(x.is_('int', isInverted: true), [
               return_(),
             ]),
           ]),
@@ -2740,10 +2728,10 @@
         h.run([
           declare(x, type: 'Object', initializer: expr('Object')),
           try_([
-            if_(x.expr.is_('String', isInverted: true), []),
+            if_(x.is_('String', isInverted: true), []),
             checkNotPromoted(x),
           ]).finally_([
-            if_(x.expr.is_('int', isInverted: true), []),
+            if_(x.is_('int', isInverted: true), []),
             checkNotPromoted(x),
           ]),
           checkNotPromoted(x),
@@ -2884,19 +2872,19 @@
         declare(z, type: 'bool', initializer: expr('bool')),
         // Create a variable that promotes x if its value is true, and y if its
         // value is false.
-        z.write(x.expr.notEq(nullLiteral).conditional(
+        z.write(x.notEq(nullLiteral).conditional(
             booleanLiteral(true),
-            y.expr
+            y
                 .notEq(nullLiteral)
                 .conditional(booleanLiteral(false), throw_(expr('Object'))))),
         checkNotPromoted(x),
         checkNotPromoted(y),
         // Simply reading the variable shouldn't promote anything.
-        z.expr,
+        z,
         checkNotPromoted(x),
         checkNotPromoted(y),
         // But reading it in an "if" condition should promote.
-        if_(z.expr, [
+        if_(z, [
           checkPromoted(x, 'int'),
           checkNotPromoted(y),
         ], [
@@ -2916,18 +2904,18 @@
         // Create a variable that promotes x if its value is true, and y if its
         // value is false.
         declare(z,
-            initializer: x.expr.notEq(nullLiteral).conditional(
+            initializer: x.notEq(nullLiteral).conditional(
                 booleanLiteral(true),
-                y.expr.notEq(nullLiteral).conditional(
+                y.notEq(nullLiteral).conditional(
                     booleanLiteral(false), throw_(expr('Object'))))),
         checkNotPromoted(x),
         checkNotPromoted(y),
         // Simply reading the variable shouldn't promote anything.
-        z.expr,
+        z,
         checkNotPromoted(x),
         checkNotPromoted(y),
         // But reading it in an "if" condition should promote.
-        if_(z.expr, [
+        if_(z, [
           checkPromoted(x, 'int'),
           checkNotPromoted(y),
         ], [
@@ -2949,19 +2937,19 @@
         declare(z, type: 'bool', initializer: expr('bool')),
         // Create a variable that promotes x if its value is true, and y if its
         // value is false.
-        z.write(x.expr.notEq(nullLiteral).conditional(
+        z.write(x.notEq(nullLiteral).conditional(
             booleanLiteral(true),
-            y.expr
+            y
                 .notEq(nullLiteral)
                 .conditional(booleanLiteral(false), throw_(expr('Object'))))),
         checkNotPromoted(w),
         checkNotPromoted(x),
         checkNotPromoted(y),
-        w.expr.nonNullAssert,
+        w.nonNullAssert,
         checkPromoted(w, 'int'),
         // Reading the value of z in an "if" condition should promote x or y,
         // and keep the promotion of w.
-        if_(z.expr, [
+        if_(z, [
           checkPromoted(w, 'int'),
           checkPromoted(x, 'int'),
           checkNotPromoted(y),
@@ -2987,7 +2975,7 @@
         y.write(nullLiteral),
         checkNotPromoted(x),
         checkNotPromoted(y),
-        if_(x.expr.eq(y.expr), [
+        if_(x.eq(y), [
           checkNotPromoted(x),
           checkNotPromoted(y),
         ], [
@@ -3004,7 +2992,7 @@
       late SsaNode<Type> ssaBeforeLoop;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         getSsaNodes((nodes) => ssaBeforeLoop = nodes[x]!),
         while_(
@@ -3026,12 +3014,12 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         while_(
             second(
                 listLiteral(elementType: 'dynamic', [
-                  x.expr.as_('int'),
+                  x.as_('int'),
                   checkNotPromoted(x),
                   localFunction([
                     x.write(expr('int?')),
@@ -3046,7 +3034,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        while_(x.expr.notEq(nullLiteral), [
+        while_(x.notEq(nullLiteral), [
           checkPromoted(x, 'int'),
         ]),
       ]);
@@ -3064,10 +3052,10 @@
         declare(x, type: 'int?', initializer: expr('int?')),
         declare(y, type: 'int?', initializer: expr('int?')),
         declare(z, type: 'int?', initializer: expr('int?')),
-        while_(x.expr.eq(nullLiteral).or(z.expr.eq(nullLiteral)), [
+        while_(x.eq(nullLiteral).or(z.eq(nullLiteral)), [
           if_(expr('bool'), [
-            x.expr.as_('int'),
-            y.expr.as_('int'),
+            x.as_('int'),
+            y.as_('int'),
             break_(),
           ]),
         ]),
@@ -3116,7 +3104,7 @@
         while_(expr('bool'), [
           x.write(expr('int?')),
           if_(expr('bool'), [break_()]),
-          if_(x.expr.is_('int'), []),
+          if_(x.is_('int'), []),
           getSsaNodes((nodes) {
             xSsaInsideLoop = nodes[x]!;
             ySsaInsideLoop = nodes[y]!;
@@ -3140,10 +3128,10 @@
       h.run([
         declare(x, type: 'Object', initializer: expr('Object')),
         declare(y, type: 'int?', initializer: expr('int?')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         getSsaNodes((nodes) => ssaBeforeWrite = nodes[x]!),
-        x.write(y.expr.eq(nullLiteral).getExpressionInfo((info) {
+        x.write(y.eq(nullLiteral).getExpressionInfo((info) {
           expect(info, isNotNull);
           writtenValueInfo = info!;
         })),
@@ -3164,7 +3152,7 @@
         declare(x, type: 'Object', initializer: expr('Object')),
         declare(y, type: 'int?', initializer: expr('int?')),
         getSsaNodes((nodes) => ssaBeforeWrite = nodes[x]!),
-        x.write(y.expr.eq(nullLiteral).getExpressionInfo((info) {
+        x.write(y.eq(nullLiteral).getExpressionInfo((info) {
           expect(info, isNotNull);
           writtenValueInfo = info!;
         })),
@@ -3199,7 +3187,7 @@
           xSsaBeforeWrite = nodes[x]!;
           ySsa = nodes[y]!;
         }),
-        x.write(y.expr),
+        x.write(y),
         getSsaNodes((nodes) {
           expect(nodes[x], isNot(xSsaBeforeWrite));
           expect(nodes[x], isNot(ySsa));
@@ -3220,7 +3208,7 @@
         getSsaNodes((nodes) => ssaBeforeWrite = nodes[x]!),
         // `y == null` is a trivial expression because y has been write
         // captured.
-        x.write(y.expr
+        x.write(y
             .eq(nullLiteral)
             .getExpressionInfo((info) => expect(info, isNotNull))),
         getSsaNodes((nodes) {
@@ -3259,7 +3247,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'Object', initializer: expr('Object')),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkPromoted(x, 'int'),
         if_(booleanLiteral(false), [
           checkPromoted(x, 'int'),
@@ -3275,7 +3263,7 @@
           x.write(expr('Object')),
         ]),
         getSsaNodes((nodes) => expect(nodes[x], isNull)),
-        x.expr.as_('int'),
+        x.as_('int'),
         checkNotPromoted(x),
         getSsaNodes((nodes) => expect(nodes[x], isNull)),
       ]);
@@ -3292,12 +3280,12 @@
         ], [
           // Promotion should work here because the write capture is in the
           // other branch.
-          x.expr.as_('int'), checkPromoted(x, 'int'),
+          x.as_('int'), checkPromoted(x, 'int'),
         ]),
         // But the promotion should be cancelled now, after the join.
         checkNotPromoted(x),
         // And further attempts to promote should fail due to the write capture.
-        x.expr.as_('int'), checkNotPromoted(x),
+        x.as_('int'), checkNotPromoted(x),
       ]);
     });
 
@@ -3308,7 +3296,7 @@
         localFunction([
           declare(b, type: 'bool', initializer: expr('bool').or(expr('bool'))),
           declare(i, isFinal: true, type: 'int'),
-          if_(b.expr, [
+          if_(b, [
             checkUnassigned(i, true),
             i.write(expr('int')),
           ], [
@@ -4930,7 +4918,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkPromoted(x, 'int'),
             ]),
           ]);
@@ -4941,7 +4929,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int'), [], [
+            if_(x.is_('int'), [], [
               checkNotPromoted(x),
             ]),
           ]);
@@ -4952,7 +4940,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkNotPromoted(x),
               x.write(expr('int')),
             ]),
@@ -4969,7 +4957,7 @@
                     .write(expr('int'))
                     .parenthesized
                     .eq(expr('int'))
-                    .and(x.expr.is_('int')),
+                    .and(x.is_('int')),
                 [
                   checkPromoted(x, 'int'),
                 ]),
@@ -4981,7 +4969,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkPromoted(x, 'int'),
             ], [
               x.write(expr('int')),
@@ -4994,7 +4982,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkNotPromoted(x),
             ]),
             localFunction([
@@ -5010,10 +4998,10 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkNotPromoted(x),
               localFunction([
-                x.expr,
+                x,
               ]),
             ]),
             x.write(expr('int')),
@@ -5027,11 +5015,11 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkNotPromoted(x),
               localFunction([
                 localFunction([
-                  x.expr,
+                  x,
                 ]),
               ]),
             ]),
@@ -5049,10 +5037,10 @@
             if_(
                 second(
                         localFunction([
-                          x.expr,
+                          x,
                         ]),
                         expr('bool'))
-                    .and(x.expr.is_('int')),
+                    .and(x.is_('int')),
                 [
                   checkPromoted(x, 'int'),
                 ]),
@@ -5067,11 +5055,11 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkPromoted(x, 'int'),
             ], [
               localFunction([
-                x.expr,
+                x,
               ]),
             ]),
             x.write(expr('int')),
@@ -5085,10 +5073,10 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkPromoted(x, 'int'),
               localFunction([
-                x.expr,
+                x,
               ]),
             ]),
           ]);
@@ -5107,7 +5095,7 @@
         var x = Var('x');
         h.run([
           declare(x, type: 'bool'),
-          if_(x.expr, []),
+          if_(x, []),
         ]);
       });
 
@@ -5118,7 +5106,7 @@
         h.run([
           declare(x, type: 'Object'),
           declare(y, type: 'Object'),
-          if_(x.expr.is_('int').and(y.expr.is_('String')), [
+          if_(x.is_('int').and(y.is_('String')), [
             checkPromoted(x, 'int'),
             checkPromoted(y, 'String'),
           ]),
@@ -5133,7 +5121,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            x.expr.is_('int').conditional(
+            x.is_('int').conditional(
                 second(checkPromoted(x, 'int'), expr('Object')),
                 expr('Object')),
           ]);
@@ -5144,7 +5132,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            x.expr.is_('int').conditional(
+            x.is_('int').conditional(
                 expr('Object'), second(checkNotPromoted(x), expr('Object'))),
           ]);
         });
@@ -5154,7 +5142,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            x.expr.is_('int').conditional(
+            x.is_('int').conditional(
                 second(
                     listLiteral(elementType: 'dynamic', [
                       checkNotPromoted(x),
@@ -5174,7 +5162,7 @@
                 .write(expr('int'))
                 .parenthesized
                 .eq(expr('int'))
-                .and(x.expr.is_('int'))
+                .and(x.is_('int'))
                 .conditional(second(checkPromoted(x, 'int'), expr('Object')),
                     expr('Object')),
           ]);
@@ -5185,7 +5173,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            x.expr.is_('int').conditional(
+            x.is_('int').conditional(
                 second(checkPromoted(x, 'int'), expr('int')),
                 x.write(expr('int'))),
           ]);
@@ -5196,7 +5184,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            x.expr.is_('int').conditional(
+            x.is_('int').conditional(
                 second(checkNotPromoted(x), expr('Object')), expr('Object')),
             localFunction([
               x.write(expr('int')),
@@ -5211,12 +5199,12 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            x.expr.is_('int').conditional(
+            x.is_('int').conditional(
                 second(
                     listLiteral(elementType: 'dynamic', [
                       checkNotPromoted(x),
                       localFunction([
-                        x.expr,
+                        x,
                       ]),
                     ]),
                     expr('Object')),
@@ -5234,10 +5222,10 @@
             declare(x, type: 'Object'),
             second(
                     localFunction([
-                      x.expr,
+                      x,
                     ]),
                     expr('Object'))
-                .and(x.expr.is_('int'))
+                .and(x.is_('int'))
                 .conditional(second(checkPromoted(x, 'int'), expr('Object')),
                     expr('Object')),
             x.write(expr('int')),
@@ -5251,11 +5239,11 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            x.expr.is_('int').conditional(
+            x.is_('int').conditional(
                 second(checkPromoted(x, 'int'), expr('Object')),
                 second(
                     localFunction([
-                      x.expr,
+                      x,
                     ]),
                     expr('Object'))),
             x.write(expr('int')),
@@ -5269,12 +5257,12 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            x.expr.is_('int').conditional(
+            x.is_('int').conditional(
                 second(
                     listLiteral(elementType: 'dynamic', [
                       checkPromoted(x, 'int'),
                       localFunction([
-                        x.expr,
+                        x,
                       ]),
                     ]),
                     expr('Object')),
@@ -5295,7 +5283,7 @@
         var x = Var('x');
         h.run([
           declare(x, type: 'bool'),
-          x.expr.conditional(expr('Object'), expr('Object')),
+          x.conditional(expr('Object'), expr('Object')),
         ]);
       });
 
@@ -5306,7 +5294,7 @@
         h.run([
           declare(x, type: 'Object'),
           declare(y, type: 'Object'),
-          x.expr.is_('int').and(y.expr.is_('String')).conditional(
+          x.is_('int').and(y.is_('String')).conditional(
               second(
                   listLiteral(elementType: 'dynamic', [
                     checkPromoted(x, 'int'),
@@ -5326,7 +5314,7 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'Object'),
-              if_(x.expr.is_('int').and(expr('bool')), [
+              if_(x.is_('int').and(expr('bool')), [
                 checkPromoted(x, 'int'),
               ]),
             ]);
@@ -5337,7 +5325,7 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'Object'),
-              if_(expr('bool').and(x.expr.is_('int')), [
+              if_(expr('bool').and(x.is_('int')), [
                 checkPromoted(x, 'int'),
               ]),
             ]);
@@ -5348,7 +5336,7 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'Object'),
-              if_(x.expr.is_('int').and(x.write(expr('bool'))), [
+              if_(x.is_('int').and(x.write(expr('bool'))), [
                 checkNotPromoted(x),
               ]),
             ]);
@@ -5361,10 +5349,8 @@
             h.run([
               declare(x, type: 'Object'),
               if_(
-                  expr('bool').and(x
-                      .write(expr('Object'))
-                      .and(x.expr.is_('int'))
-                      .parenthesized),
+                  expr('bool').and(
+                      x.write(expr('Object')).and(x.is_('int')).parenthesized),
                   [
                     checkNotPromoted(x),
                   ]),
@@ -5376,7 +5362,7 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'Object'),
-              if_(x.expr.is_('int').and(expr('bool')), [
+              if_(x.is_('int').and(expr('bool')), [
                 checkNotPromoted(x),
               ]),
               localFunction([
@@ -5392,9 +5378,7 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'Object'),
-              x.expr
-                  .is_('int')
-                  .and(second(checkPromoted(x, 'int'), expr('bool'))),
+              x.is_('int').and(second(checkPromoted(x, 'int'), expr('bool'))),
             ]);
           });
 
@@ -5407,7 +5391,7 @@
                   .write(expr('int'))
                   .parenthesized
                   .eq(expr('int'))
-                  .and(x.expr.is_('int'))
+                  .and(x.is_('int'))
                   .parenthesized
                   .and(second(checkNotPromoted(x), expr('bool'))),
             ]);
@@ -5418,7 +5402,7 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'Object'),
-              x.expr
+              x
                   .is_('int')
                   .and(second(checkNotPromoted(x), x.write(expr('bool')))),
             ]);
@@ -5429,7 +5413,7 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'Object'),
-              x.expr.is_('int').and(second(checkNotPromoted(x), expr('bool'))),
+              x.is_('int').and(second(checkNotPromoted(x), expr('bool'))),
               localFunction([
                 x.write(expr('int')),
               ]),
@@ -5443,11 +5427,11 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'Object'),
-              x.expr.is_('int').and(second(
+              x.is_('int').and(second(
                   listLiteral(elementType: 'dynamic', [
                     checkNotPromoted(x),
                     localFunction([
-                      x.expr,
+                      x,
                     ]),
                   ]),
                   expr('bool'))),
@@ -5464,10 +5448,10 @@
               declare(x, type: 'Object'),
               second(
                       localFunction([
-                        x.expr,
+                        x,
                       ]),
                       expr('Object'))
-                  .and(x.expr.is_('int'))
+                  .and(x.is_('int'))
                   .parenthesized
                   .and(second(checkPromoted(x, 'int'), expr('bool'))),
               x.write(expr('int')),
@@ -5481,11 +5465,11 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'Object'),
-              x.expr.is_('int').and(second(
+              x.is_('int').and(second(
                   listLiteral(elementType: 'dynamic', [
                     checkPromoted(x, 'int'),
                     localFunction([
-                      x.expr,
+                      x,
                     ]),
                   ]),
                   expr('bool'))),
@@ -5505,9 +5489,9 @@
                 x
                     .write(expr('Object'))
                     .parenthesized
-                    .and(x.expr.is_('int'))
+                    .and(x.is_('int'))
                     .parenthesized
-                    .and(x.expr.is_('num')),
+                    .and(x.is_('num')),
                 [
                   checkPromoted(x, 'int'),
                 ]),
@@ -5519,7 +5503,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('num').and(x.expr.is_('int')), [
+            if_(x.is_('num').and(x.is_('int')), [
               checkPromoted(x, 'int'),
             ]),
           ]);
@@ -5532,16 +5516,12 @@
           h.run([
             declare(x, type: 'Object'),
             declare(y, type: 'Object'),
-            x.expr
-                .is_('int')
-                .and(y.expr.is_('String'))
-                .parenthesized
-                .and(second(
-                    listLiteral(elementType: 'dynamic', [
-                      checkPromoted(x, 'int'),
-                      checkPromoted(y, 'String'),
-                    ]),
-                    expr('bool'))),
+            x.is_('int').and(y.is_('String')).parenthesized.and(second(
+                listLiteral(elementType: 'dynamic', [
+                  checkPromoted(x, 'int'),
+                  checkPromoted(y, 'String'),
+                ]),
+                expr('bool'))),
           ]);
         });
 
@@ -5552,7 +5532,7 @@
           h.run([
             declare(x, type: 'bool'),
             declare(y, type: 'bool'),
-            if_(x.expr.and(y.expr), []),
+            if_(x.and(y), []),
           ]);
         });
 
@@ -5569,7 +5549,7 @@
         var x = Var('x');
         h.run([
           declare(x, type: 'Object'),
-          if_(x.expr.is_('int').or(x.expr.is_('int')), [
+          if_(x.is_('int').or(x.is_('int')), [
             checkNotPromoted(x),
           ], [
             checkNotPromoted(x),
@@ -5585,7 +5565,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkPromoted(x, 'int'),
             ], [
               checkNotPromoted(x),
@@ -5598,7 +5578,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('int', isInverted: true), [
+            if_(x.is_('int', isInverted: true), [
               checkNotPromoted(x),
             ], [
               checkNotPromoted(x),
@@ -5612,7 +5592,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'String'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkNotPromoted(x),
             ], [
               checkNotPromoted(x),
@@ -5625,8 +5605,8 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('num'), [
-              if_(x.expr.is_('int'), [
+            if_(x.is_('num'), [
+              if_(x.is_('int'), [
                 checkPromoted(x, 'int'),
               ], [
                 checkPromoted(x, 'num'),
@@ -5642,8 +5622,8 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'Object'),
-            if_(x.expr.is_('String'), [
-              if_(x.expr.is_('int'), [
+            if_(x.is_('String'), [
+              if_(x.is_('int'), [
                 checkPromoted(x, 'String'),
               ], [
                 checkPromoted(x, 'String'),
@@ -5658,7 +5638,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'T'),
-            if_(x.expr.is_('int'), [
+            if_(x.is_('int'), [
               checkPromoted(x, 'T&int'),
             ]),
           ]);
@@ -5679,7 +5659,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'Object'),
-        if_(x.expr.is_('int').eq(expr('Object')).thenStmt(block([])), [
+        if_(x.is_('int').eq(expr('Object')).thenStmt(block([])), [
           checkNotPromoted(x),
         ]),
       ]);
@@ -5692,7 +5672,7 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'Object'),
-        if_(x.expr.is_('int').eq(expr('Object')).parenthesized, [
+        if_(x.is_('int').eq(expr('Object')).parenthesized, [
           checkNotPromoted(x),
         ]),
       ]);
@@ -5720,13 +5700,13 @@
       late Expression writeExpression;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.eq(nullLiteral), [
+        if_(x.eq(nullLiteral), [
           return_(),
         ]),
         checkPromoted(x, 'int'),
         (writeExpression = x.write(expr('int?'))),
         checkNotPromoted(x),
-        x.expr.whyNotPromoted((reasons) {
+        x.whyNotPromoted((reasons) {
           expect(reasons.keys, unorderedEquals([Type('int')]));
           var nonPromotionReason =
               reasons.values.single as DemoteViaExplicitWrite<Var>;
@@ -5740,16 +5720,16 @@
       late Expression writeExpression;
       h.run([
         declare(x, type: 'Object?', initializer: expr('Object?')),
-        if_(x.expr.isNot('int?'), [
+        if_(x.isNot('int?'), [
           return_(),
         ]),
-        if_(x.expr.eq(nullLiteral), [
+        if_(x.eq(nullLiteral), [
           return_(),
         ]),
         checkPromoted(x, 'int'),
         (writeExpression = x.write(expr('Object?'))),
         checkNotPromoted(x),
-        x.expr.whyNotPromoted((reasons) {
+        x.whyNotPromoted((reasons) {
           expect(reasons.keys, unorderedEquals([Type('int'), Type('int?')]));
           expect((reasons[Type('int')] as DemoteViaExplicitWrite<Var>).node,
               same(writeExpression));
@@ -5764,13 +5744,13 @@
       late Pattern writePattern;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.eq(nullLiteral), [
+        if_(x.eq(nullLiteral), [
           return_(),
         ]),
         checkPromoted(x, 'int'),
         (writePattern = x.pattern()).assign(expr('int?')),
         checkNotPromoted(x),
-        x.expr.whyNotPromoted((reasons) {
+        x.whyNotPromoted((reasons) {
           expect(reasons.keys, unorderedEquals([Type('int')]));
           var nonPromotionReason =
               reasons.values.single as DemoteViaExplicitWrite<Var>;
@@ -5784,7 +5764,7 @@
       late Expression writeExpression;
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.eq(nullLiteral), [
+        if_(x.eq(nullLiteral), [
           return_(),
         ]),
         checkPromoted(x, 'int'),
@@ -5793,7 +5773,7 @@
         if_(expr('bool'), [
           return_(),
         ]),
-        x.expr.whyNotPromoted((reasons) {
+        x.whyNotPromoted((reasons) {
           expect(reasons.keys, unorderedEquals([Type('int')]));
           var nonPromotionReason =
               reasons.values.single as DemoteViaExplicitWrite<Var>;
@@ -5807,17 +5787,17 @@
       late Expression writeExpression;
       h.run([
         declare(x, type: 'Object', initializer: expr('Object')),
-        if_(x.expr.is_('int', isInverted: true), [
+        if_(x.is_('int', isInverted: true), [
           return_(),
         ]),
         checkPromoted(x, 'int'),
         (writeExpression = x.write(expr('Object'))),
         checkNotPromoted(x),
-        if_(x.expr.is_('num', isInverted: true), [
+        if_(x.is_('num', isInverted: true), [
           return_(),
         ]),
         checkPromoted(x, 'num'),
-        x.expr.whyNotPromoted((reasons) {
+        x.whyNotPromoted((reasons) {
           var nonPromotionReason =
               reasons[Type('int')] as DemoteViaExplicitWrite<Var>;
           expect(nonPromotionReason.node, same(writeExpression));
@@ -5829,17 +5809,17 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'int?', initializer: expr('int?')),
-        if_(x.expr.eq(nullLiteral), [
+        if_(x.eq(nullLiteral), [
           return_(),
         ]),
         checkPromoted(x, 'int'),
         x.write(expr('int?')),
         checkNotPromoted(x),
-        if_(x.expr.eq(nullLiteral), [
+        if_(x.eq(nullLiteral), [
           return_(),
         ]),
         checkPromoted(x, 'int'),
-        x.expr.whyNotPromoted((reasons) {
+        x.whyNotPromoted((reasons) {
           expect(reasons, isEmpty);
         }),
       ]);
@@ -5881,10 +5861,10 @@
         var x = Var('x');
         h.run([
           declare(x, type: 'C', initializer: expr('C')),
-          if_(x.expr.property('field').eq(nullLiteral), [
+          if_(x.property('field').eq(nullLiteral), [
             return_(),
           ]),
-          x.expr.property('field').whyNotPromoted((reasons) {
+          x.property('field').whyNotPromoted((reasons) {
             expect(reasons.keys, unorderedEquals([Type('Object')]));
             var nonPromotionReason = reasons.values.single;
             expect(nonPromotionReason, TypeMatcher<PropertyNotPromoted>());
@@ -5934,11 +5914,11 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'C', initializer: expr('C')),
-        if_(x.expr.property('_field').eq(nullLiteral), [
+        if_(x.property('_field').eq(nullLiteral), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field'), 'Object'),
-        x.expr.property('_field').checkType('Object'),
+        checkPromoted(x.property('_field'), 'Object'),
+        x.property('_field').checkType('Object'),
       ]);
     });
 
@@ -5959,11 +5939,11 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'C', initializer: expr('C')),
-        if_(x.expr.property('_field').eq(nullLiteral), [
+        if_(x.property('_field').eq(nullLiteral), [
           return_(),
         ]),
-        checkNotPromoted(x.expr.property('_field')),
-        x.expr.property('_field').checkType('Object?'),
+        checkNotPromoted(x.property('_field')),
+        x.property('_field').checkType('Object?'),
       ]);
     });
 
@@ -5984,14 +5964,14 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'C', initializer: expr('C')),
-        if_(x.expr.property('_field').eq(nullLiteral), [
+        if_(x.property('_field').eq(nullLiteral), [
           return_(),
         ]),
-        if_(x.expr.property('_field').isNot('int'), [
+        if_(x.property('_field').isNot('int'), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field'), 'int'),
-        x.expr.property('_field').checkType('int'),
+        checkPromoted(x.property('_field'), 'int'),
+        x.property('_field').checkType('int'),
       ]);
     });
 
@@ -6018,16 +5998,16 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'B', initializer: expr('B')),
-        if_(x.expr.property('_field').eq(nullLiteral), [
+        if_(x.property('_field').eq(nullLiteral), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field'), 'Object'),
-        x.expr.property('_field').checkType('Object'),
-        if_(x.expr.isNot('C'), [
+        checkPromoted(x.property('_field'), 'Object'),
+        x.property('_field').checkType('Object'),
+        if_(x.isNot('C'), [
           return_(),
         ]),
-        checkNotPromoted(x.expr.property('_field')),
-        x.expr.property('_field').checkType('num?'),
+        checkNotPromoted(x.property('_field')),
+        x.property('_field').checkType('num?'),
       ]);
     });
 
@@ -6039,16 +6019,16 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'B', initializer: expr('B')),
-        if_(x.expr.property('_field').isNot('int'), [
+        if_(x.property('_field').isNot('int'), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field'), 'int'),
-        x.expr.property('_field').checkType('int'),
-        if_(x.expr.isNot('C'), [
+        checkPromoted(x.property('_field'), 'int'),
+        x.property('_field').checkType('int'),
+        if_(x.isNot('C'), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field'), 'int'),
-        x.expr.property('_field').checkType('int'),
+        checkPromoted(x.property('_field'), 'int'),
+        x.property('_field').checkType('int'),
       ]);
     });
 
@@ -6060,15 +6040,15 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'B', initializer: expr('B')),
-        if_(x.expr.is_('C'), [
-          if_(x.expr.property('_field').notEq(nullLiteral), [
-            checkPromoted(x.expr.property('_field'), 'Object'),
-            x.expr.property('_field').checkType('Object'),
+        if_(x.is_('C'), [
+          if_(x.property('_field').notEq(nullLiteral), [
+            checkPromoted(x.property('_field'), 'Object'),
+            x.property('_field').checkType('Object'),
           ]),
         ]),
-        if_(x.expr.property('_field').notEq(nullLiteral), [
-          checkNotPromoted(x.expr.property('_field')),
-          x.expr.property('_field').checkType('Object?'),
+        if_(x.property('_field').notEq(nullLiteral), [
+          checkNotPromoted(x.property('_field')),
+          x.property('_field').checkType('Object?'),
         ]),
       ]);
     });
@@ -6081,14 +6061,14 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'B', initializer: expr('B')),
-        if_(x.expr.property('_field').notEq(nullLiteral), [
-          checkNotPromoted(x.expr.property('_field')),
-          x.expr.property('_field').checkType('Object?'),
+        if_(x.property('_field').notEq(nullLiteral), [
+          checkNotPromoted(x.property('_field')),
+          x.property('_field').checkType('Object?'),
         ]),
-        if_(x.expr.is_('C'), [
-          if_(x.expr.property('_field').notEq(nullLiteral), [
-            checkPromoted(x.expr.property('_field'), 'Object'),
-            x.expr.property('_field').checkType('Object'),
+        if_(x.is_('C'), [
+          if_(x.property('_field').notEq(nullLiteral), [
+            checkPromoted(x.property('_field'), 'Object'),
+            x.property('_field').checkType('Object'),
           ]),
         ]),
       ]);
@@ -6109,10 +6089,10 @@
         if_(this_.property('_field2').isNot('String?'), [
           return_(),
         ]),
-        if_(x.expr.property('_field1').isNot('int'), [
+        if_(x.property('_field1').isNot('int'), [
           return_(),
         ]),
-        if_(y.expr.property('_field1').isNot('double'), [
+        if_(y.property('_field1').isNot('double'), [
           return_(),
         ]),
         checkPromoted(thisProperty('_field1'), 'String'),
@@ -6123,14 +6103,14 @@
         thisProperty('_field2').checkType('String?'),
         checkPromoted(this_.property('_field2'), 'String?'),
         this_.property('_field2').checkType('String?'),
-        checkPromoted(x.expr.property('_field1'), 'int'),
-        x.expr.property('_field1').checkType('int'),
-        checkNotPromoted(x.expr.property('_field2')),
-        x.expr.property('_field2').checkType('Object?'),
-        checkPromoted(y.expr.property('_field1'), 'double'),
-        y.expr.property('_field1').checkType('double'),
-        checkNotPromoted(y.expr.property('_field2')),
-        y.expr.property('_field2').checkType('Object?'),
+        checkPromoted(x.property('_field1'), 'int'),
+        x.property('_field1').checkType('int'),
+        checkNotPromoted(x.property('_field2')),
+        x.property('_field2').checkType('Object?'),
+        checkPromoted(y.property('_field1'), 'double'),
+        y.property('_field1').checkType('double'),
+        checkNotPromoted(y.property('_field2')),
+        y.property('_field2').checkType('Object?'),
       ]);
     });
 
@@ -6140,14 +6120,14 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'C', initializer: expr('C')),
-        if_(x.expr.property('_field').isNot('String'), [
+        if_(x.property('_field').isNot('String'), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field'), 'String'),
-        x.expr.property('_field').checkType('String'),
+        checkPromoted(x.property('_field'), 'String'),
+        x.property('_field').checkType('String'),
         x.write(expr('C')),
-        checkNotPromoted(x.expr.property('_field')),
-        x.expr.property('_field').checkType('Object?'),
+        checkNotPromoted(x.property('_field')),
+        x.property('_field').checkType('Object?'),
       ]);
     });
 
@@ -6158,14 +6138,14 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'C', initializer: expr('C')),
-        if_(x.expr.property('_field1').property('_field2').isNot('String'), [
+        if_(x.property('_field1').property('_field2').isNot('String'), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field1').property('_field2'), 'String'),
-        x.expr.property('_field1').property('_field2').checkType('String'),
+        checkPromoted(x.property('_field1').property('_field2'), 'String'),
+        x.property('_field1').property('_field2').checkType('String'),
         x.write(expr('C')),
-        checkNotPromoted(x.expr.property('_field1').property('_field2')),
-        x.expr.property('_field1').property('_field2').checkType('Object?'),
+        checkNotPromoted(x.property('_field1').property('_field2')),
+        x.property('_field1').property('_field2').checkType('Object?'),
       ]);
     });
 
@@ -6175,14 +6155,14 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'C', initializer: expr('C')),
-        if_(x.expr.property('_field').isNot('String'), [
+        if_(x.property('_field').isNot('String'), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field'), 'String'),
-        x.expr.property('_field').checkType('String'),
+        checkPromoted(x.property('_field'), 'String'),
+        x.property('_field').checkType('String'),
         while_(expr('bool'), [
-          checkNotPromoted(x.expr.property('_field')),
-          x.expr.property('_field').checkType('Object?'),
+          checkNotPromoted(x.property('_field')),
+          x.property('_field').checkType('Object?'),
           x.write(expr('C')),
         ]),
       ]);
@@ -6195,14 +6175,14 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'C', initializer: expr('C')),
-        if_(x.expr.property('_field1').property('_field2').isNot('String'), [
+        if_(x.property('_field1').property('_field2').isNot('String'), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field1').property('_field2'), 'String'),
-        x.expr.property('_field1').property('_field2').checkType('String'),
+        checkPromoted(x.property('_field1').property('_field2'), 'String'),
+        x.property('_field1').property('_field2').checkType('String'),
         while_(expr('bool'), [
-          checkNotPromoted(x.expr.property('_field1').property('_field2')),
-          x.expr.property('_field1').property('_field2').checkType('Object?'),
+          checkNotPromoted(x.property('_field1').property('_field2')),
+          x.property('_field1').property('_field2').checkType('Object?'),
           x.write(expr('C')),
         ]),
       ]);
@@ -6214,16 +6194,16 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'C', initializer: expr('C')),
-        if_(x.expr.property('_field').isNot('String'), [
+        if_(x.property('_field').isNot('String'), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field'), 'String'),
-        x.expr.property('_field').checkType('String'),
+        checkPromoted(x.property('_field'), 'String'),
+        x.property('_field').checkType('String'),
         localFunction([
           x.write(expr('C')),
         ]),
-        checkNotPromoted(x.expr.property('_field')),
-        x.expr.property('_field').checkType('Object?'),
+        checkNotPromoted(x.property('_field')),
+        x.property('_field').checkType('Object?'),
       ]);
     });
 
@@ -6234,16 +6214,16 @@
       var x = Var('x');
       h.run([
         declare(x, type: 'C', initializer: expr('C')),
-        if_(x.expr.property('_field1').property('_field2').isNot('String'), [
+        if_(x.property('_field1').property('_field2').isNot('String'), [
           return_(),
         ]),
-        checkPromoted(x.expr.property('_field1').property('_field2'), 'String'),
-        x.expr.property('_field1').property('_field2').checkType('String'),
+        checkPromoted(x.property('_field1').property('_field2'), 'String'),
+        x.property('_field1').property('_field2').checkType('String'),
         localFunction([
           x.write(expr('C')),
         ]),
-        checkNotPromoted(x.expr.property('_field1').property('_field2')),
-        x.expr.property('_field1').property('_field2').checkType('Object?'),
+        checkNotPromoted(x.property('_field1').property('_field2')),
+        x.property('_field1').property('_field2').checkType('Object?'),
       ]);
     });
 
@@ -6256,11 +6236,11 @@
         localFunction([
           x.write(expr('C')),
         ]),
-        if_(x.expr.property('_field').isNot('String'), [
+        if_(x.property('_field').isNot('String'), [
           return_(),
         ]),
-        checkNotPromoted(x.expr.property('_field')),
-        x.expr.property('_field').checkType('Object?'),
+        checkNotPromoted(x.property('_field')),
+        x.property('_field').checkType('Object?'),
       ]);
     });
 
@@ -6274,11 +6254,11 @@
         localFunction([
           x.write(expr('C')),
         ]),
-        if_(x.expr.property('_field1').property('_field2').isNot('String'), [
+        if_(x.property('_field1').property('_field2').isNot('String'), [
           return_(),
         ]),
-        checkNotPromoted(x.expr.property('_field1').property('_field2')),
-        x.expr.property('_field1').property('_field2').checkType('Object?'),
+        checkNotPromoted(x.property('_field1').property('_field2')),
+        x.property('_field1').property('_field2').checkType('Object?'),
       ]);
     });
 
@@ -6323,9 +6303,9 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('C')),
-            x.expr.property('_field').as_('int'),
-            checkPromoted(x.expr.property('_field'), 'int'),
-            x.expr.cascade([
+            x.property('_field').as_('int'),
+            checkPromoted(x.property('_field'), 'int'),
+            x.cascade([
               (v) => v.property('_field').checkType('int'),
               (v) => v.property('_field').checkType('int'),
             ]),
@@ -6337,9 +6317,9 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('C')),
-            x.expr.property('_field').as_('int'),
-            checkPromoted(x.expr.property('_field'), 'int'),
-            x.expr
+            x.property('_field').as_('int'),
+            checkPromoted(x.property('_field'), 'int'),
+            x
                 .cascade([(v) => v.property('_field').checkType('int')])
                 .property('_field')
                 .checkType('int'),
@@ -6350,8 +6330,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('int?')),
-            x.expr
-                .cascade([(v) => v.invokeMethod('toString', [])]).nonNullAssert,
+            x.cascade([(v) => v.invokeMethod('toString', [])]).nonNullAssert,
             checkNotPromoted(x),
           ]);
         });
@@ -6377,7 +6356,7 @@
             localFunction([
               x.write(expr('C')),
             ]),
-            x.expr
+            x
                 .cascade([
                   (v) => v.property('_field').checkType('int?').nonNullAssert,
                   (v) => v.property('_field').checkType('int'),
@@ -6394,9 +6373,9 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('C')),
-            x.expr.property('_field').as_('int'),
-            checkPromoted(x.expr.property('_field'), 'int'),
-            x.expr.cascade(isNullAware: true, [
+            x.property('_field').as_('int'),
+            checkPromoted(x.property('_field'), 'int'),
+            x.cascade(isNullAware: true, [
               (v) => v.property('_field').checkType('int'),
               (v) => v.property('_field').checkType('int'),
             ]),
@@ -6408,9 +6387,9 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('C')),
-            x.expr.property('_field').as_('int'),
-            checkPromoted(x.expr.property('_field'), 'int'),
-            x.expr
+            x.property('_field').as_('int'),
+            checkPromoted(x.property('_field'), 'int'),
+            x
                 .cascade(
                     isNullAware: true,
                     [(v) => v.property('_field').checkType('int')])
@@ -6423,7 +6402,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('int?')),
-            x.expr.cascade(
+            x.cascade(
                 isNullAware: true,
                 [(v) => v.invokeMethod('toString', [])]).nonNullAssert,
             checkNotPromoted(x),
@@ -6459,7 +6438,7 @@
             localFunction([
               x.write(expr('C')),
             ]),
-            x.expr
+            x
                 .cascade(isNullAware: true, [
                   (v) => v.property('_field').checkType('int?').nonNullAssert,
                   (v) => v.property('_field').checkType('int'),
@@ -6485,7 +6464,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'int?'),
-            x.expr.nonNullAssert,
+            x.nonNullAssert,
             checkPromoted(x, 'int'),
             x.pattern().assign(expr('int?')),
             checkNotPromoted(x),
@@ -6496,7 +6475,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'num?'),
-            x.expr.nonNullAssert,
+            x.nonNullAssert,
             checkPromoted(x, 'num'),
             x.pattern().assign(expr('int')),
             checkPromoted(x, 'num'),
@@ -6517,7 +6496,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'int?'),
-            x.expr.nonNullAssert,
+            x.nonNullAssert,
             checkPromoted(x, 'int'),
             x.pattern().assign(expr('int').checkContext('int')),
           ]);
@@ -6529,7 +6508,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'num'),
-            if_(x.expr.is_('int'), []),
+            if_(x.is_('int'), []),
             checkNotPromoted(x),
             x.pattern().assign(expr('int')),
             checkPromoted(x, 'int'),
@@ -6578,7 +6557,7 @@
           h.run([
             declare(x, type: 'int'),
             declare(y, initializer: expr('dynamic')),
-            x.pattern().and(wildcard()..errorId = 'WILDCARD').assign(y.expr),
+            x.pattern().and(wildcard()..errorId = 'WILDCARD').assign(y),
             checkNotPromoted(y),
           ], expectedErrors: {
             'unnecessaryWildcardPattern(pattern: WILDCARD, '
@@ -6604,8 +6583,8 @@
           h.run([
             declare(x, type: 'int?'),
             declare(b, type: 'bool'),
-            b.pattern().assign(x.expr.notEq(nullLiteral)),
-            if_(b.expr, [
+            b.pattern().assign(x.notEq(nullLiteral)),
+            if_(b, [
               // `x` is promoted because `b` is known to equal `x != null`.
               checkPromoted(x, 'int'),
             ]),
@@ -6618,8 +6597,8 @@
           h.run([
             declare(x, type: 'int?'),
             declare(b, type: 'bool'),
-            b.pattern().parenthesized.assign(x.expr.notEq(nullLiteral)),
-            if_(b.expr, [
+            b.pattern().parenthesized.assign(x.notEq(nullLiteral)),
+            if_(b, [
               // `x` is promoted because `b` is known to equal `x != null`.
               checkPromoted(x, 'int'),
             ]),
@@ -6636,8 +6615,8 @@
             objectPattern(
                     requiredType: 'bool',
                     fields: [b.pattern().recordField('foo')])
-                .assign(x.expr.notEq(nullLiteral)),
-            if_(b.expr, [
+                .assign(x.notEq(nullLiteral)),
+            if_(b, [
               // Even though the RHS of the pattern is `x != null`, `x` is not
               // promoted because the pattern for `b` is in a subpattern
               // position.
@@ -6657,7 +6636,7 @@
             recordPattern([y.pattern().recordField()])
                 .and(wildcard(expectInferredType: '(int,)')
                   ..errorId = 'WILDCARD')
-                .assign(x.expr),
+                .assign(x),
             checkNotPromoted(x),
           ], expectedErrors: {
             'unnecessaryWildcardPattern(pattern: WILDCARD, '
@@ -6674,7 +6653,7 @@
             recordPattern([y.pattern().recordField()])
                 .and(wildcard(expectInferredType: '(int,)')
                   ..errorId = 'WILDCARD')
-                .assign(x.expr),
+                .assign(x),
             checkNotPromoted(x),
           ], expectedErrors: {
             'unnecessaryWildcardPattern(pattern: WILDCARD, '
@@ -6689,7 +6668,7 @@
         var x = Var('x');
         h.run([
           declare(x, type: 'Object?'),
-          ifCase(x.expr, wildcard(expectInferredType: 'String').as_('String'), [
+          ifCase(x, wildcard(expectInferredType: 'String').as_('String'), [
             checkPromoted(x, 'String'),
           ]),
         ]);
@@ -6700,7 +6679,7 @@
         h.run([
           declare(x, type: 'num'),
           ifCase(
-              x.expr,
+              x,
               wildcard(expectInferredType: 'Object').as_('Object')
                 ..errorId = 'PATTERN',
               [
@@ -6716,7 +6695,7 @@
         var x = Var('x');
         h.run([
           declare(x, type: 'num'),
-          ifCase(x.expr, wildcard(expectInferredType: 'String').as_('String'), [
+          ifCase(x, wildcard(expectInferredType: 'String').as_('String'), [
             checkNotPromoted(x),
           ]),
         ]);
@@ -6727,7 +6706,7 @@
         h.run([
           declare(x, type: 'Object?'),
           ifCase(
-              x.expr,
+              x,
               objectPattern(requiredType: 'int', fields: []).as_('num').and(
                   wildcard(expectInferredType: 'num')..errorId = 'WILDCARD'),
               [
@@ -6757,7 +6736,7 @@
         h.run([
           declare(x, initializer: expr('Object?')),
           ifCase(
-              x.expr,
+              x,
               wildcard()
                   .as_('int')
                   .and(wildcard().as_('num')..errorId = 'AS_NUM')
@@ -6776,8 +6755,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('(num,)')),
-            ifCase(
-                x.expr, recordPattern([wildcard().as_('int').recordField()]), [
+            ifCase(x, recordPattern([wildcard().as_('int').recordField()]), [
               checkPromoted(x, '(int,)'),
             ]),
           ]);
@@ -6788,7 +6766,7 @@
           h.run([
             declare(x, initializer: expr('(num,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   (wildcard().as_('Object')..errorId = 'CAST').recordField()
                 ]),
@@ -6805,8 +6783,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('(num,)')),
-            ifCase(x.expr,
-                recordPattern([wildcard().as_('String').recordField()]), [
+            ifCase(x, recordPattern([wildcard().as_('String').recordField()]), [
               checkNotPromoted(x),
             ]),
           ]);
@@ -6865,7 +6842,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('int?')),
-          ifCase(x.expr, nullLiteral.pattern, [
+          ifCase(x, nullLiteral.pattern, [
             checkReachable(true),
             checkNotPromoted(x),
           ], [
@@ -6882,7 +6859,7 @@
         h.run([
           declare(x, initializer: expr('int?')),
           switch_(
-              x.expr,
+              x,
               [
                 nullLiteral.pattern.then([
                   checkReachable(true),
@@ -6903,7 +6880,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('int?')),
-          switch_(x.expr, [
+          switch_(x, [
             wildcard().when(second(x.write(expr('int?')), expr('bool'))).then([
               break_(),
             ]),
@@ -6947,7 +6924,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('(Object,)')),
-          ifCase(x.expr, recordPattern([intLiteral(1).pattern.recordField()]), [
+          ifCase(x, recordPattern([intLiteral(1).pattern.recordField()]), [
             checkNotPromoted(x),
           ]),
         ]);
@@ -6961,7 +6938,7 @@
           declare(x, initializer: expr('List<dynamic>')),
           patternForIn(
             wildcard(type: 'int'),
-            x.expr,
+            x,
             [],
           ),
           checkNotPromoted(x),
@@ -6977,7 +6954,7 @@
           listLiteral(elementType: 'Object', [
             patternForInElement(
               wildcard(type: 'int'),
-              x.expr,
+              x,
               expr('Object'),
             ),
           ]),
@@ -6994,7 +6971,7 @@
           listLiteral(elementType: 'String', [
             ifCaseElement(
                 expr('Object'),
-                wildcard().when(x.expr.notEq(nullLiteral)),
+                wildcard().when(x.notEq(nullLiteral)),
                 second(
                     listLiteral(elementType: 'dynamic', [
                       checkReachable(true),
@@ -7018,7 +6995,7 @@
           declare(x, type: 'num'),
           listLiteral(elementType: 'String', [
             ifCaseElement(
-                x.expr,
+                x,
                 y.pattern(type: 'int'),
                 second(
                     listLiteral(elementType: 'dynamic', [
@@ -7042,7 +7019,7 @@
         var x = Var('x');
         h.run([
           declare(x, type: 'int?'),
-          ifCase(expr('Object'), wildcard().when(x.expr.notEq(nullLiteral)), [
+          ifCase(expr('Object'), wildcard().when(x.notEq(nullLiteral)), [
             checkReachable(true),
             checkPromoted(x, 'int'),
           ], [
@@ -7057,7 +7034,7 @@
         var y = Var('y');
         h.run([
           declare(x, type: 'num'),
-          ifCase(x.expr, y.pattern(type: 'int'), [
+          ifCase(x, y.pattern(type: 'int'), [
             checkReachable(true),
             checkPromoted(x, 'int'),
           ], [
@@ -7073,8 +7050,7 @@
         h.run([
           declare(x, type: 'int?'),
           declare(y, type: 'String?'),
-          ifCase(
-              x.expr, wildcard(type: 'int').when(y.expr.notEq(nullLiteral)), [
+          ifCase(x, wildcard(type: 'int').when(y.notEq(nullLiteral)), [
             checkReachable(true),
             checkPromoted(x, 'int'),
             checkPromoted(y, 'String'),
@@ -7094,7 +7070,7 @@
           h.run([
             declare(x, type: 'num'),
             ifCase(
-                x.expr,
+                x,
                 wildcard(type: 'int').and(
                     wildcard(expectInferredType: 'int')..errorId = 'WILDCARD'),
                 [
@@ -7125,7 +7101,7 @@
         h.run([
           declare(x, type: 'Object'),
           ifCase(
-              x.expr,
+              x,
               wildcard(type: 'num').and(wildcard(type: 'int').and(
                   wildcard(expectInferredType: 'int')..errorId = 'WILDCARD')),
               [
@@ -7143,7 +7119,7 @@
           h.run([
             declare(x, initializer: expr('(Object,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'int')
                       .and(wildcard(type: 'num')..errorId = 'NUM')
@@ -7163,7 +7139,7 @@
           h.run([
             declare(x, initializer: expr('(Object,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'num').and(wildcard(type: 'int')).recordField()
                 ]),
@@ -7178,7 +7154,7 @@
           h.run([
             declare(x, initializer: expr('(num,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'int')
                       .and(wildcard(type: 'num')..errorId = 'NUM')
@@ -7198,7 +7174,7 @@
           h.run([
             declare(x, initializer: expr('(num,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   (wildcard(type: 'num')..errorId = 'NUM')
                       .and(wildcard(type: 'int'))
@@ -7218,7 +7194,7 @@
           h.run([
             declare(x, initializer: expr('(num,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'int')
                       .and(wildcard(type: 'Object')..errorId = 'OBJECT')
@@ -7238,7 +7214,7 @@
           h.run([
             declare(x, initializer: expr('(num,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   (wildcard(type: 'Object')..errorId = 'OBJECT')
                       .and(wildcard(type: 'int'))
@@ -7258,7 +7234,7 @@
           h.run([
             declare(x, initializer: expr('(int,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   (wildcard(type: 'num')..errorId = 'NUM')
                       .and(wildcard(type: 'Object')..errorId = 'OBJECT')
@@ -7280,7 +7256,7 @@
           h.run([
             declare(x, initializer: expr('(int,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   (wildcard(type: 'Object')..errorId = 'OBJECT')
                       .and(wildcard(type: 'num')..errorId = 'NUM')
@@ -7307,7 +7283,7 @@
           h.run([
             declare(x, initializer: expr('Object')),
             ifCase(
-                x.expr,
+                x,
                 objectPattern(requiredType: 'num', fields: [])
                     .and(objectPattern(requiredType: 'int', fields: []))
                     .or(objectPattern(requiredType: 'num', fields: [])),
@@ -7323,7 +7299,7 @@
           h.run([
             declare(x, initializer: expr('Object')),
             ifCase(
-                x.expr,
+                x,
                 objectPattern(requiredType: 'num', fields: []).or(
                     objectPattern(requiredType: 'num', fields: [])
                         .and(objectPattern(requiredType: 'int', fields: []))),
@@ -7465,7 +7441,7 @@
           h.run([
             declare(x, initializer: expr('(Object,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'int').or(wildcard(type: 'num')).recordField()
                 ]),
@@ -7484,7 +7460,7 @@
           h.run([
             declare(x, initializer: expr('(Object,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'num').or(wildcard(type: 'int')).recordField()
                 ]),
@@ -7503,7 +7479,7 @@
           h.run([
             declare(x, initializer: expr('(Object,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'num').or(wildcard(type: 'num')).recordField()
                 ]),
@@ -7518,7 +7494,7 @@
           h.run([
             declare(x, initializer: expr('(num,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'int')
                       .or(wildcard(type: 'Object'))
@@ -7535,7 +7511,7 @@
           h.run([
             declare(x, initializer: expr('(num,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'Object')
                       .or(wildcard(type: 'int'))
@@ -7552,7 +7528,7 @@
           h.run([
             declare(x, initializer: expr('(int,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'num')
                       .or(wildcard(type: 'Object'))
@@ -7569,7 +7545,7 @@
           h.run([
             declare(x, initializer: expr('(int,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'Object')
                       .or(wildcard(type: 'num'))
@@ -7589,7 +7565,7 @@
           h.run([
             declare(x, initializer: expr('(Object?,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'int')
                       .or(wildcard(type: 'double'))
@@ -7669,7 +7645,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('Object?')),
-          ifCase(x.expr, listPattern([wildcard()], elementType: 'int'), [
+          ifCase(x, listPattern([wildcard()], elementType: 'int'), [
             checkPromoted(x, 'List<int>'),
           ]),
         ]);
@@ -7681,7 +7657,7 @@
         h.run([
           declare(x, initializer: expr('Object?')),
           ifCase(
-              x.expr,
+              x,
               wildcard()
                   .as_('List<int>')
                   .and(listPattern([], elementType: 'num'))
@@ -7696,7 +7672,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('List<int>')),
-          ifCase(x.expr, listPattern([], elementType: 'int'), [
+          ifCase(x, listPattern([], elementType: 'int'), [
             checkReachable(true),
           ], [
             checkReachable(true),
@@ -7710,7 +7686,7 @@
           h.run([
             declare(x, initializer: expr('(Iterable<Object>,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   listPattern([wildcard(type: 'int')], elementType: 'num')
                       .recordField()
@@ -7726,7 +7702,7 @@
           h.run([
             declare(x, initializer: expr('(List<num>,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   listPattern([wildcard(type: 'int')], elementType: 'Object')
                       .recordField()
@@ -7742,7 +7718,7 @@
           h.run([
             declare(x, initializer: expr('(List<int?>,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   listPattern([wildcard(type: 'int')], elementType: 'num')
                       .recordField()
@@ -7761,7 +7737,7 @@
         h.run([
           declare(x, initializer: expr('Object?')),
           ifCase(
-              x.expr,
+              x,
               mapPattern([mapPatternEntry(intLiteral(0), wildcard())],
                   keyType: 'int', valueType: 'String'),
               [
@@ -7792,7 +7768,7 @@
         h.run([
           declare(x, initializer: expr('Object?')),
           ifCase(
-              x.expr,
+              x,
               wildcard()
                   .as_('Map<int, int>')
                   .and(mapPattern([
@@ -7810,7 +7786,7 @@
         h.run([
           declare(x, initializer: expr('Map<int, int>')),
           ifCase(
-              x.expr,
+              x,
               mapPattern([
                 mapPatternEntry(expr('Object'), wildcard()),
               ], keyType: 'int', valueType: 'int'),
@@ -7829,7 +7805,7 @@
           h.run([
             declare(x, initializer: expr('(Map<num?, Object>?,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   mapPattern([
                     mapPatternEntry(intLiteral(0), wildcard(type: 'int'))
@@ -7847,7 +7823,7 @@
           h.run([
             declare(x, initializer: expr('(Map<int, num>,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   mapPattern([
                     mapPatternEntry(intLiteral(0), wildcard(type: 'int'))
@@ -7865,7 +7841,7 @@
           h.run([
             declare(x, initializer: expr('(Map<int, int?>,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   mapPattern([
                     mapPatternEntry(intLiteral(0), wildcard(type: 'int'))
@@ -7894,7 +7870,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('Object?')),
-            switch_(x.expr, [
+            switch_(x, [
               wildcard()
                   .when(second(x.write(expr('Object?')), expr('bool')))
                   .then([
@@ -7911,7 +7887,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('Object?')),
-            ifCase(x.expr, wildcard().nullAssert, [
+            ifCase(x, wildcard().nullAssert, [
               checkPromoted(x, 'Object'),
             ], [
               checkNotPromoted(x),
@@ -7936,7 +7912,7 @@
           h.run([
             declare(x, initializer: expr('Object?')),
             ifCase(
-                x.expr,
+                x,
                 objectPattern(
                     requiredType: 'T',
                     fields: [wildcard().nullAssert.recordField('foo')]),
@@ -7982,7 +7958,7 @@
         h.run([
           declare(x, initializer: expr('Object?')),
           ifCase(
-              x.expr,
+              x,
               wildcard()
                   .as_('int?')
                   .and(wildcard().nullAssert)
@@ -7997,7 +7973,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('(int?,)')),
-          ifCase(x.expr, recordPattern([wildcard().nullAssert.recordField()]), [
+          ifCase(x, recordPattern([wildcard().nullAssert.recordField()]), [
             checkPromoted(x, '(int,)'),
           ]),
         ]);
@@ -8018,7 +7994,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('Object?')),
-            switch_(x.expr, [
+            switch_(x, [
               wildcard()
                   .when(second(x.write(expr('Object?')), expr('bool')))
                   .then([
@@ -8035,7 +8011,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('Object?')),
-            ifCase(x.expr, wildcard().nullCheck, [
+            ifCase(x, wildcard().nullCheck, [
               checkPromoted(x, 'Object'),
             ], [
               checkNotPromoted(x),
@@ -8060,7 +8036,7 @@
           h.run([
             declare(x, initializer: expr('Object?')),
             ifCase(
-                x.expr,
+                x,
                 objectPattern(
                     requiredType: 'T',
                     fields: [wildcard().nullCheck.recordField('foo')]),
@@ -8106,7 +8082,7 @@
         h.run([
           declare(x, initializer: expr('Object?')),
           ifCase(
-              x.expr,
+              x,
               wildcard()
                   .as_('int?')
                   .and(wildcard().nullCheck)
@@ -8121,7 +8097,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('(int?,)')),
-          ifCase(x.expr, recordPattern([wildcard().nullCheck.recordField()]), [
+          ifCase(x, recordPattern([wildcard().nullCheck.recordField()]), [
             checkPromoted(x, '(int,)'),
           ]),
         ]);
@@ -8133,7 +8109,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('Object?')),
-          ifCase(x.expr, objectPattern(requiredType: 'int', fields: []), [
+          ifCase(x, objectPattern(requiredType: 'int', fields: []), [
             checkPromoted(x, 'int'),
           ]),
         ]);
@@ -8145,7 +8121,7 @@
         h.run([
           declare(x, initializer: expr('Object?')),
           ifCase(
-              x.expr,
+              x,
               wildcard()
                   .as_('int')
                   .and(objectPattern(requiredType: 'num', fields: []))
@@ -8162,7 +8138,7 @@
           h.run([
             declare(x, initializer: expr('(num,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   objectPattern(requiredType: 'int', fields: []).recordField()
                 ]),
@@ -8177,7 +8153,7 @@
           h.run([
             declare(x, initializer: expr('(num,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   objectPattern(requiredType: 'Object', fields: [])
                       .recordField()
@@ -8193,7 +8169,7 @@
           h.run([
             declare(x, initializer: expr('(num,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   objectPattern(requiredType: 'String', fields: [])
                       .recordField()
@@ -8227,7 +8203,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('num')),
-          wildcard().as_('int').assign(x.expr),
+          wildcard().as_('int').assign(x),
           checkNotPromoted(x),
         ]);
       });
@@ -8238,7 +8214,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('num')),
-          match(wildcard().as_('int'), x.expr),
+          match(wildcard().as_('int'), x),
           checkNotPromoted(x),
         ]);
       });
@@ -8249,7 +8225,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('Object?')),
-          ifCase(x.expr, recordPattern([wildcard().recordField()]), [
+          ifCase(x, recordPattern([wildcard().recordField()]), [
             checkPromoted(x, '(Object?,)'),
           ]),
         ]);
@@ -8261,7 +8237,7 @@
           h.run([
             declare(x, initializer: expr('Object?')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'int').recordField(),
                   wildcard(type: 'String').recordField()
@@ -8277,7 +8253,7 @@
           h.run([
             declare(x, initializer: expr('Object?')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   wildcard(type: 'int').recordField('i'),
                   wildcard(type: 'String').recordField('s')
@@ -8296,7 +8272,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('Object')),
-          ifCase(x.expr, recordPattern([wildcard(type: 'int').recordField()]), [
+          ifCase(x, recordPattern([wildcard(type: 'int').recordField()]), [
             checkPromoted(x, '(int,)'),
             x.write(expr('(num,)')),
             checkPromoted(x, '(Object?,)'),
@@ -8308,7 +8284,7 @@
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('(Object?,)')),
-          ifCase(x.expr, recordPattern([wildcard().as_('int').recordField()]), [
+          ifCase(x, recordPattern([wildcard().as_('int').recordField()]), [
             checkPromoted(x, '(int,)'),
           ], [
             checkReachable(
@@ -8334,7 +8310,7 @@
         h.run([
           declare(x, initializer: expr('Object?')),
           ifCase(
-              x.expr,
+              x,
               wildcard()
                   .as_('(int,)')
                   .and(recordPattern([wildcard().recordField()]))
@@ -8351,7 +8327,7 @@
           h.run([
             declare(x, initializer: expr('((num,),)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   recordPattern([wildcard(type: 'int').recordField()])
                       .recordField()
@@ -8367,7 +8343,7 @@
           h.run([
             declare(x, initializer: expr('Never')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   recordPattern([wildcard(type: 'num').recordField()])
                       .recordField()
@@ -8383,7 +8359,7 @@
           h.run([
             declare(x, initializer: expr('String')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern([
                   recordPattern([wildcard(type: 'num').recordField()])
                       .recordField()
@@ -8400,7 +8376,7 @@
         h.run([
           declare(x, initializer: expr('(Null, Object?)')),
           ifCase(
-              x.expr,
+              x,
               recordPattern([
                 relationalPattern('!=', nullLiteral).recordField(),
                 wildcard(type: 'error').recordField()
@@ -8456,7 +8432,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('int?')),
-            ifCase(x.expr, relationalPattern('==', nullLiteral), [
+            ifCase(x, relationalPattern('==', nullLiteral), [
               checkReachable(true),
               checkNotPromoted(x),
             ], [
@@ -8470,7 +8446,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('int?')),
-            switch_(x.expr, [
+            switch_(x, [
               wildcard()
                   .when(second(x.write(expr('int?')), expr('bool')))
                   .then([
@@ -8520,7 +8496,7 @@
             h.run([
               declare(x, initializer: expr('(Object?,)')),
               ifCase(
-                  x.expr,
+                  x,
                   recordPattern(
                       [relationalPattern('==', expr('Object')).recordField()]),
                   [
@@ -8537,7 +8513,7 @@
             h.run([
               declare(x, initializer: expr('(Object?,)')),
               ifCase(
-                  x.expr,
+                  x,
                   recordPattern(
                       [relationalPattern('==', nullLiteral).recordField()]),
                   [
@@ -8573,7 +8549,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('int?')),
-            ifCase(x.expr, relationalPattern('!=', nullLiteral), [
+            ifCase(x, relationalPattern('!=', nullLiteral), [
               checkReachable(true),
               checkPromoted(x, 'int'),
             ], [
@@ -8587,7 +8563,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('int?')),
-            switch_(x.expr, [
+            switch_(x, [
               wildcard()
                   .when(second(x.write(expr('int?')), expr('bool')))
                   .then([
@@ -8642,7 +8618,7 @@
             h.run([
               declare(x, initializer: expr('(Object?,)')),
               ifCase(
-                  x.expr,
+                  x,
                   recordPattern(
                       [relationalPattern('!=', expr('Object')).recordField()]),
                   [
@@ -8658,7 +8634,7 @@
             h.run([
               declare(x, initializer: expr('(Object?,)')),
               ifCase(
-                  x.expr,
+                  x,
                   recordPattern(
                       [relationalPattern('!=', nullLiteral).recordField()]),
                   [
@@ -8691,7 +8667,7 @@
           h.run([
             declare(x, initializer: expr('(int,)')),
             ifCase(
-                x.expr,
+                x,
                 recordPattern(
                     [relationalPattern('>', intLiteral(0)).recordField()]),
                 [
@@ -8708,7 +8684,7 @@
         h.run([
           declare(x, type: 'int?'),
           switchExpr(expr('Object'), [
-            wildcard().when(x.expr.notEq(nullLiteral)).thenExpr(second(
+            wildcard().when(x.notEq(nullLiteral)).thenExpr(second(
                 listLiteral(elementType: 'dynamic', [
                   checkReachable(true),
                   checkPromoted(x, 'int'),
@@ -8732,7 +8708,7 @@
           h.run([
             declare(x, type: 'int?'),
             switchExpr(expr('Object?'), [
-              wildcard().when(x.expr.eq(nullLiteral)).thenExpr(intLiteral(0)),
+              wildcard().when(x.eq(nullLiteral)).thenExpr(intLiteral(0)),
               wildcard()
                   .thenExpr(second(checkPromoted(x, 'int'), intLiteral(1))),
             ]),
@@ -8748,7 +8724,7 @@
             declare(x, type: 'int?'),
             switchExpr(expr('Object?'), [
               wildcard(type: 'String')
-                  .when(x.expr.eq(nullLiteral))
+                  .when(x.eq(nullLiteral))
                   .thenExpr(intLiteral(0)),
               wildcard().thenExpr(second(
                   listLiteral(elementType: 'dynamic', [
@@ -8765,7 +8741,7 @@
         var y = Var('y');
         h.run([
           declare(x, type: 'num'),
-          switchExpr(x.expr, [
+          switchExpr(x, [
             y.pattern(type: 'int').thenExpr(second(
                 listLiteral(elementType: 'dynamic', [
                   checkReachable(true),
@@ -8789,7 +8765,7 @@
         // scrutinee in the RHS of the `&&`.
         h.run([
           declare(x, initializer: expr('Object')),
-          switchExpr(x.expr, [
+          switchExpr(x, [
             wildcard(type: 'int')
                 .and(wildcard(expectInferredType: 'int')..errorId = 'WILDCARD1')
                 .thenExpr(second(checkPromoted(x, 'int'), intLiteral(0))),
@@ -8819,9 +8795,9 @@
         // is still used for type inference in the later `case var y`.
         h.run([
           declare(x, initializer: expr('Object')),
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'),
-          switchExpr(x.expr, [
+          switchExpr(x, [
             wildcard()
                 .when(second(x.write(expr('Object')), expr('bool')))
                 .thenExpr(intLiteral(0)),
@@ -8859,7 +8835,7 @@
           declare(x, type: 'int?'),
           switch_(expr('Object'), [
             switchStatementMember([
-              wildcard().when(x.expr.notEq(nullLiteral))
+              wildcard().when(x.notEq(nullLiteral))
             ], [
               checkReachable(true),
               checkPromoted(x, 'int'),
@@ -8882,7 +8858,7 @@
           h.run([
             declare(x, type: 'int?'),
             switch_(expr('Object?'), [
-              wildcard().when(x.expr.eq(nullLiteral)).then([break_()]),
+              wildcard().when(x.eq(nullLiteral)).then([break_()]),
               wildcard().then([
                 checkPromoted(x, 'int'),
               ]),
@@ -8898,9 +8874,7 @@
           h.run([
             declare(x, type: 'int?'),
             switch_(expr('Object?'), [
-              wildcard(type: 'String')
-                  .when(x.expr.eq(nullLiteral))
-                  .then([break_()]),
+              wildcard(type: 'String').when(x.eq(nullLiteral)).then([break_()]),
               wildcard().then([
                 checkNotPromoted(x),
               ]),
@@ -8914,7 +8888,7 @@
         var y = Var('y');
         h.run([
           declare(x, type: 'num'),
-          switch_(x.expr, [
+          switch_(x, [
             switchStatementMember([
               y.pattern(type: 'int')
             ], [
@@ -8939,7 +8913,7 @@
             switchStatementMember([
               wildcard(type: 'int')
             ], [
-              x.expr.as_('int'),
+              x.as_('int'),
             ]),
             switchStatementMember([default_], [return_()])
           ]),
@@ -9055,11 +9029,11 @@
           h.run([
             declare(x, initializer: expr('Object')),
             declare(y, initializer: expr('Object')),
-            switch_(x.expr, [
+            switch_(x, [
               wildcard(type: 'num').then([
                 checkPromoted(x, 'num'),
                 checkNotPromoted(y),
-                switch_(y.expr, [
+                switch_(y, [
                   wildcard(type: 'int').then([
                     checkPromoted(x, 'num'),
                     checkPromoted(y, 'int'),
@@ -9087,7 +9061,7 @@
         // scrutinee in the RHS of the `&&`.
         h.run([
           declare(x, initializer: expr('Object')),
-          switch_(x.expr, [
+          switch_(x, [
             wildcard(type: 'int')
                 .and(wildcard(expectInferredType: 'int')..errorId = 'WILDCARD1')
                 .then([
@@ -9122,9 +9096,9 @@
         // is still used for type inference in the later `case var y`.
         h.run([
           declare(x, initializer: expr('Object')),
-          x.expr.as_('int'),
+          x.as_('int'),
           checkPromoted(x, 'int'),
-          switch_(x.expr, [
+          switch_(x, [
             wildcard()
                 .when(second(x.write(expr('Object')), expr('bool')))
                 .then([break_()]),
@@ -9178,7 +9152,7 @@
           // ` case num() && int(): case num():` retains promotion to `num`
           h.run([
             declare(x, initializer: expr('Object')),
-            switch_(x.expr, [
+            switch_(x, [
               switchStatementMember([
                 objectPattern(requiredType: 'num', fields: [])
                     .and(objectPattern(requiredType: 'int', fields: [])),
@@ -9195,7 +9169,7 @@
           // `case num(): case num() && int():` retains promotion to `num`
           h.run([
             declare(x, initializer: expr('Object')),
-            switch_(x.expr, [
+            switch_(x, [
               switchStatementMember([
                 objectPattern(requiredType: 'num', fields: []),
                 objectPattern(requiredType: 'num', fields: [])
@@ -9289,7 +9263,7 @@
                 recordPattern([
                   intLiteral(1).pattern.recordField(),
                   x2.pattern(type: 'int?').recordField()
-                ]).when(x2.expr.notEq(nullLiteral)),
+                ]).when(x2.notEq(nullLiteral)),
               ], [
                 checkPromoted(x, 'int'),
               ])
@@ -9308,15 +9282,12 @@
           h.run([
             switch_(expr('Object?'), [
               switchStatementMember([
-                a1
-                    .pattern(type: 'String?')
-                    .nullCheck
-                    .when(a1.expr.is_('Never')),
-                a2.pattern(type: 'String?').when(a2.expr.notEq(nullLiteral)),
+                a1.pattern(type: 'String?').nullCheck.when(a1.is_('Never')),
+                a2.pattern(type: 'String?').when(a2.notEq(nullLiteral)),
                 a3
                     .pattern(type: 'String?')
                     .nullAssert
-                    .when(a3.expr.eq(intLiteral(1))),
+                    .when(a3.eq(intLiteral(1))),
               ], [
                 checkPromoted(a, 'String'),
               ]),
@@ -9488,7 +9459,7 @@
           var y = Var('y');
           h.run([
             declare(x, type: 'int'),
-            ifCase(x.expr, y.pattern(type: 'num'), [
+            ifCase(x, y.pattern(type: 'num'), [
               checkReachable(true),
               checkNotPromoted(x),
             ], [
@@ -9520,7 +9491,7 @@
             var y = Var('y');
             h.run([
               declare(x, type: 'num'),
-              ifCase(x.expr, y.pattern(type: 'int'), [
+              ifCase(x, y.pattern(type: 'int'), [
                 checkReachable(true),
                 checkPromoted(x, 'int'),
               ], [
@@ -9535,7 +9506,7 @@
             var y = Var('y');
             h.run([
               declare(x, type: 'int?'),
-              ifCase(x.expr, y.pattern(type: 'Null'), [
+              ifCase(x, y.pattern(type: 'Null'), [
                 checkReachable(true),
                 checkPromoted(x, 'Null'),
               ], [
@@ -9553,7 +9524,7 @@
         h.run([
           declare(x, initializer: expr('Object')),
           ifCase(
-              x.expr,
+              x,
               objectPattern(
                   requiredType: 'num',
                   fields: [y.pattern(type: 'int').recordField('sign')]),
@@ -9571,7 +9542,7 @@
         h.run([
           declare(x, initializer: expr('Object?')),
           ifCase(
-              x.expr,
+              x,
               wildcard()
                   .as_('int')
                   .and(y.pattern(type: 'num'))
@@ -9613,8 +9584,7 @@
           var y = Var('y');
           h.run([
             declare(x, initializer: expr('(num,)')),
-            ifCase(
-                x.expr, recordPattern([y.pattern(type: 'int').recordField()]), [
+            ifCase(x, recordPattern([y.pattern(type: 'int').recordField()]), [
               checkPromoted(x, '(int,)'),
             ]),
           ]);
@@ -9625,8 +9595,8 @@
           var y = Var('y');
           h.run([
             declare(x, initializer: expr('(num,)')),
-            ifCase(x.expr,
-                recordPattern([y.pattern(type: 'Object').recordField()]), [
+            ifCase(
+                x, recordPattern([y.pattern(type: 'Object').recordField()]), [
               checkNotPromoted(x),
             ]),
           ]);
@@ -9637,8 +9607,8 @@
           var y = Var('y');
           h.run([
             declare(x, initializer: expr('(num,)')),
-            ifCase(x.expr,
-                recordPattern([y.pattern(type: 'String').recordField()]), [
+            ifCase(
+                x, recordPattern([y.pattern(type: 'String').recordField()]), [
               checkNotPromoted(x),
             ]),
           ]);
@@ -9666,7 +9636,7 @@
           var x = Var('x');
           h.run([
             declare(x, type: 'int'),
-            ifCase(x.expr, wildcard(type: 'num'), [
+            ifCase(x, wildcard(type: 'num'), [
               checkReachable(true),
               checkNotPromoted(x),
             ], [
@@ -9696,7 +9666,7 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'num'),
-              ifCase(x.expr, wildcard(type: 'int'), [
+              ifCase(x, wildcard(type: 'int'), [
                 checkReachable(true),
                 checkPromoted(x, 'int'),
               ], [
@@ -9710,7 +9680,7 @@
             var x = Var('x');
             h.run([
               declare(x, type: 'int?'),
-              ifCase(x.expr, wildcard(type: 'Null'), [
+              ifCase(x, wildcard(type: 'Null'), [
                 checkReachable(true),
                 checkPromoted(x, 'Null'),
               ], [
@@ -9727,7 +9697,7 @@
         h.run([
           declare(x, initializer: expr('Object')),
           ifCase(
-              x.expr,
+              x,
               objectPattern(
                   requiredType: 'num',
                   fields: [wildcard(type: 'int').recordField('sign')]),
@@ -9744,7 +9714,7 @@
         h.run([
           declare(x, initializer: expr('Object?')),
           ifCase(
-              x.expr,
+              x,
               wildcard()
                   .as_('int')
                   .and(wildcard(type: 'num')..errorId = 'WILDCARD')
@@ -9763,8 +9733,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('(num,)')),
-            ifCase(
-                x.expr, recordPattern([wildcard(type: 'int').recordField()]), [
+            ifCase(x, recordPattern([wildcard(type: 'int').recordField()]), [
               checkPromoted(x, '(int,)'),
             ]),
           ]);
@@ -9774,8 +9743,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('(num,)')),
-            ifCase(x.expr,
-                recordPattern([wildcard(type: 'Object').recordField()]), [
+            ifCase(x, recordPattern([wildcard(type: 'Object').recordField()]), [
               checkNotPromoted(x),
             ]),
           ]);
@@ -9785,8 +9753,7 @@
           var x = Var('x');
           h.run([
             declare(x, initializer: expr('(num,)')),
-            ifCase(x.expr,
-                recordPattern([wildcard(type: 'String').recordField()]), [
+            ifCase(x, recordPattern([wildcard(type: 'String').recordField()]), [
               checkNotPromoted(x),
             ]),
           ]);
@@ -9819,10 +9786,10 @@
         declare(x, initializer: expr('FutureOr<int>')),
         declare(y, initializer: expr('FutureOr<String>')),
         ifCase(
-            x.expr,
+            x,
             wildcard(type: 'int').when(second(
                 localFunction([
-                  ifCase(y.expr, wildcard(type: 'String'), [
+                  ifCase(y, wildcard(type: 'String'), [
                     checkPromoted(x, 'int'),
                     checkPromoted(y, 'String'),
                   ], [
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index 6de9725..31d01f5 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -44,8 +44,12 @@
 
 Expression get this_ => new This._(location: computeLocation());
 
-Statement assert_(Expression condition, [Expression? message]) =>
-    new Assert._(condition, message, location: computeLocation());
+Statement assert_(ProtoExpression condition, [ProtoExpression? message]) {
+  var location = computeLocation();
+  return new Assert._(condition.asExpression(location: location),
+      message?.asExpression(location: location),
+      location: location);
+}
 
 Statement block(List<ProtoStatement> statements) =>
     new Block._(statements, location: computeLocation());
@@ -122,22 +126,24 @@
     {bool isLate = false,
     bool isFinal = false,
     String? type,
-    Expression? initializer,
+    ProtoExpression? initializer,
     String? expectInferredType}) {
   var location = computeLocation();
   return new Declare._(
       new VariablePattern._(
           type == null ? null : Type(type), variable, expectInferredType,
           location: location),
-      initializer,
+      initializer?.asExpression(location: location),
       isLate: isLate,
       isFinal: isFinal,
       location: location);
 }
 
-Statement do_(List<ProtoStatement> body, Expression condition) {
+Statement do_(List<ProtoStatement> body, ProtoExpression condition) {
   var location = computeLocation();
-  return Do._(Block._(body, location: location), condition, location: location);
+  return Do._(Block._(body, location: location),
+      condition.asExpression(location: location),
+      location: location);
 }
 
 /// Creates a pseudo-expression having type [typeStr] that otherwise has no
@@ -148,12 +154,16 @@
 /// Creates a conventional `for` statement.  Optional boolean [forCollection]
 /// indicates that this `for` statement is actually a collection element, so
 /// `null` should be passed to [for_bodyBegin].
-Statement for_(ProtoStatement? initializer, Expression? condition,
-    Expression? updater, List<ProtoStatement> body,
+Statement for_(ProtoStatement? initializer, ProtoExpression? condition,
+    ProtoExpression? updater, List<ProtoStatement> body,
     {bool forCollection = false}) {
   var location = computeLocation();
-  return new For._(initializer?.asStatement, condition, updater,
-      Block._(body, location: location), forCollection,
+  return new For._(
+      initializer?.asStatement(location: location),
+      condition?.asExpression(location: location),
+      updater?.asExpression(location: location),
+      Block._(body, location: location),
+      forCollection,
       location: location);
 }
 
@@ -166,9 +176,10 @@
 ///       for (x in iterable) { ... }
 ///     }
 Statement forEachWithNonVariable(
-    Expression iterable, List<ProtoStatement> body) {
+    ProtoExpression iterable, List<ProtoStatement> body) {
   var location = computeLocation();
-  return new ForEach._(null, iterable, Block._(body, location: location), false,
+  return new ForEach._(null, iterable.asExpression(location: location),
+      Block._(body, location: location), false,
       location: location);
 }
 
@@ -180,9 +191,11 @@
 ///       for (var x in iterable) { ... }
 ///     }
 Statement forEachWithVariableDecl(
-    Var variable, Expression iterable, List<ProtoStatement> body) {
-  return new ForEach._(variable, iterable, block(body), true,
-      location: computeLocation());
+    Var variable, ProtoExpression iterable, List<ProtoStatement> body) {
+  var location = computeLocation();
+  return new ForEach._(
+      variable, iterable.asExpression(location: location), block(body), true,
+      location: location);
 }
 
 /// Creates a "for each" statement where the identifier being assigned to by the
@@ -194,28 +207,30 @@
 ///       for (x in iterable) { ... }
 ///     }
 Statement forEachWithVariableSet(
-    Var variable, Expression iterable, List<ProtoStatement> body) {
+    Var variable, ProtoExpression iterable, List<ProtoStatement> body) {
   var location = computeLocation();
-  return new ForEach._(
-      variable, iterable, Block._(body, location: location), false,
+  return new ForEach._(variable, iterable.asExpression(location: location),
+      Block._(body, location: location), false,
       location: location);
 }
 
-Statement if_(Expression condition, List<ProtoStatement> ifTrue,
+Statement if_(ProtoExpression condition, List<ProtoStatement> ifTrue,
     [List<ProtoStatement>? ifFalse]) {
   var location = computeLocation();
-  return new If._(condition, Block._(ifTrue, location: location),
+  return new If._(
+      condition.asExpression(location: location),
+      Block._(ifTrue, location: location),
       ifFalse == null ? null : Block._(ifFalse, location: location),
       location: location);
 }
 
-Statement ifCase(Expression expression, PossiblyGuardedPattern pattern,
+Statement ifCase(ProtoExpression expression, PossiblyGuardedPattern pattern,
     List<ProtoStatement> ifTrue,
     [List<ProtoStatement>? ifFalse]) {
   var location = computeLocation();
   var guardedPattern = pattern._asGuardedPattern;
   return IfCase(
-    expression,
+    expression.asExpression(location: location),
     guardedPattern.pattern,
     guardedPattern.guard,
     Block._(ifTrue, location: location),
@@ -225,7 +240,7 @@
 }
 
 CollectionElement ifCaseElement(
-  Expression expression,
+  ProtoExpression expression,
   PossiblyGuardedPattern pattern,
   ProtoCollectionElement ifTrue, [
   ProtoCollectionElement? ifFalse,
@@ -233,20 +248,23 @@
   var location = computeLocation();
   var guardedPattern = pattern._asGuardedPattern;
   return new IfCaseElement(
-    expression,
+    expression.asExpression(location: location),
     guardedPattern.pattern,
     guardedPattern.guard,
-    ifTrue.asCollectionElement,
-    ifFalse?.asCollectionElement,
+    ifTrue.asCollectionElement(location: location),
+    ifFalse?.asCollectionElement(location: location),
     location: location,
   );
 }
 
-CollectionElement ifElement(Expression condition, ProtoCollectionElement ifTrue,
+CollectionElement ifElement(
+    ProtoExpression condition, ProtoCollectionElement ifTrue,
     [ProtoCollectionElement? ifFalse]) {
   var location = computeLocation();
   return new IfElement._(
-      condition, ifTrue.asCollectionElement, ifFalse?.asCollectionElement,
+      condition.asExpression(location: location),
+      ifTrue.asCollectionElement(location: location),
+      ifFalse?.asCollectionElement(location: location),
       location: location);
 }
 
@@ -260,10 +278,13 @@
 /// [elementType] is the explicit type argument of the list literal.
 /// TODO(paulberry): support list literals with an inferred type argument.
 Expression listLiteral(List<ProtoCollectionElement> elements,
-        {required String elementType}) =>
-    ListLiteral._([
-      for (var element in elements) element.asCollectionElement
-    ], Type(elementType), location: computeLocation());
+    {required String elementType}) {
+  var location = computeLocation();
+  return ListLiteral._([
+    for (var element in elements)
+      element.asCollectionElement(location: location)
+  ], Type(elementType), location: location);
+}
 
 Pattern listPattern(List<ListPatternElement> elements, {String? elementType}) =>
     ListPattern._(elementType == null ? null : Type(elementType), elements,
@@ -289,8 +310,10 @@
       location: location);
 }
 
-MapPatternElement mapPatternEntry(Expression key, Pattern value) {
-  return MapPatternEntry._(key, value, location: computeLocation());
+MapPatternElement mapPatternEntry(ProtoExpression key, Pattern value) {
+  var location = computeLocation();
+  return MapPatternEntry._(key.asExpression(location: location), value,
+      location: location);
 }
 
 MapPatternElement mapPatternRestElement([Pattern? pattern]) =>
@@ -312,10 +335,12 @@
   );
 }
 
-Statement match(Pattern pattern, Expression initializer,
-        {bool isLate = false, bool isFinal = false}) =>
-    new Declare._(pattern, initializer,
-        isLate: isLate, isFinal: isFinal, location: computeLocation());
+Statement match(Pattern pattern, ProtoExpression initializer,
+    {bool isLate = false, bool isFinal = false}) {
+  var location = computeLocation();
+  return new Declare._(pattern, initializer.asExpression(location: location),
+      isLate: isLate, isFinal: isFinal, location: location);
+}
 
 Pattern objectPattern({
   required String requiredType,
@@ -340,13 +365,13 @@
 ///     }
 Statement patternForIn(
   Pattern pattern,
-  Expression expression,
+  ProtoExpression expression,
   List<ProtoStatement> body, {
   bool hasAwait = false,
 }) {
   var location = computeLocation();
-  return new PatternForIn(
-      pattern, expression, Block._(body, location: location),
+  return new PatternForIn(pattern, expression.asExpression(location: location),
+      Block._(body, location: location),
       hasAwait: hasAwait, location: location);
 }
 
@@ -358,22 +383,28 @@
 ///     }
 CollectionElement patternForInElement(
   Pattern pattern,
-  Expression expression,
+  ProtoExpression expression,
   ProtoCollectionElement body, {
   bool hasAwait = false,
 }) {
   var location = computeLocation();
-  return new PatternForInElement(pattern, expression, body.asCollectionElement,
-      hasAwait: hasAwait, location: location);
+  return new PatternForInElement(
+      pattern,
+      expression.asExpression(location: location),
+      body.asCollectionElement(location: location),
+      hasAwait: hasAwait,
+      location: location);
 }
 
 Pattern recordPattern(List<RecordPatternField> fields) =>
     RecordPattern._(fields, location: computeLocation());
 
-Pattern relationalPattern(String operator, Expression operand,
+Pattern relationalPattern(String operator, ProtoExpression operand,
     {String? errorId}) {
-  var result =
-      RelationalPattern._(operator, operand, location: computeLocation());
+  var location = computeLocation();
+  var result = RelationalPattern._(
+      operator, operand.asExpression(location: location),
+      location: location);
   if (errorId != null) {
     result.errorId = errorId;
   }
@@ -390,30 +421,41 @@
 /// This can be useful in situations where a test needs to verify certain
 /// properties, or establish certain preconditions, before the analysis reaches
 /// a certain subexpression.
-Expression second(Expression first, Expression second) =>
-    Second._(first, second, location: computeLocation());
+Expression second(ProtoExpression first, ProtoExpression second) {
+  var location = computeLocation();
+  return Second._(first.asExpression(location: location),
+      second.asExpression(location: location),
+      location: location);
+}
 
 PromotableLValue superProperty(String name) => new ThisOrSuperProperty._(name,
     location: computeLocation(), isSuperAccess: true);
 
-Statement switch_(Expression expression, List<SwitchStatementMember> cases,
-        {bool? isLegacyExhaustive,
-        bool? expectHasDefault,
-        bool? expectIsExhaustive,
-        bool? expectLastCaseTerminates,
-        bool? expectRequiresExhaustivenessValidation,
-        String? expectScrutineeType}) =>
-    new SwitchStatement(expression, cases, isLegacyExhaustive,
-        location: computeLocation(),
-        expectHasDefault: expectHasDefault,
-        expectIsExhaustive: expectIsExhaustive,
-        expectLastCaseTerminates: expectLastCaseTerminates,
-        expectRequiresExhaustivenessValidation:
-            expectRequiresExhaustivenessValidation,
-        expectScrutineeType: expectScrutineeType);
+Statement switch_(ProtoExpression expression, List<SwitchStatementMember> cases,
+    {bool? isLegacyExhaustive,
+    bool? expectHasDefault,
+    bool? expectIsExhaustive,
+    bool? expectLastCaseTerminates,
+    bool? expectRequiresExhaustivenessValidation,
+    String? expectScrutineeType}) {
+  var location = computeLocation();
+  return new SwitchStatement(
+      expression.asExpression(location: location), cases, isLegacyExhaustive,
+      location: location,
+      expectHasDefault: expectHasDefault,
+      expectIsExhaustive: expectIsExhaustive,
+      expectLastCaseTerminates: expectLastCaseTerminates,
+      expectRequiresExhaustivenessValidation:
+          expectRequiresExhaustivenessValidation,
+      expectScrutineeType: expectScrutineeType);
+}
 
-Expression switchExpr(Expression expression, List<ExpressionCase> cases) =>
-    new SwitchExpression._(expression, cases, location: computeLocation());
+Expression switchExpr(ProtoExpression expression, List<ExpressionCase> cases) {
+  var location = computeLocation();
+  return new SwitchExpression._(
+      expression.asExpression(location: location), cases,
+      location: location);
+}
 
 SwitchStatementMember switchStatementMember(
   List<ProtoSwitchHead> cases,
@@ -432,8 +474,11 @@
 PromotableLValue thisProperty(String name) => new ThisOrSuperProperty._(name,
     location: computeLocation(), isSuperAccess: false);
 
-Expression throw_(Expression operand) =>
-    new Throw._(operand, location: computeLocation());
+Expression throw_(ProtoExpression operand) {
+  var location = computeLocation();
+  return new Throw._(operand.asExpression(location: location),
+      location: location);
+}
 
 TryBuilder try_(List<ProtoStatement> body) {
   var location = computeLocation();
@@ -441,9 +486,10 @@
       location: location);
 }
 
-Statement while_(Expression condition, List<ProtoStatement> body) {
+Statement while_(ProtoExpression condition, List<ProtoStatement> body) {
   var location = computeLocation();
-  return new While._(condition, Block._(body, location: location),
+  return new While._(condition.asExpression(location: location),
+      Block._(body, location: location),
       location: location);
 }
 
@@ -509,7 +555,9 @@
   final List<Statement> statements;
 
   Block._(List<ProtoStatement> statements, {required super.location})
-      : statements = [for (var s in statements) s.asStatement];
+      : statements = [
+          for (var s in statements) s.asStatement(location: location)
+        ];
 
   @override
   void preVisit(PreVisitor visitor) {
@@ -1005,12 +1053,15 @@
   CollectionElement({required super.location}) : super._();
 
   @override
-  CollectionElement get asCollectionElement => this;
+  CollectionElement asCollectionElement({required String location}) => this;
 
   @override
-  CollectionElement checkIR(String expectedIR) =>
-      CheckCollectionElementIR._(asCollectionElement, expectedIR,
-          location: computeLocation());
+  CollectionElement checkIR(String expectedIR) {
+    var location = computeLocation();
+    return CheckCollectionElementIR._(
+        asCollectionElement(location: location), expectedIR,
+        location: location);
+  }
 
   void preVisit(PreVisitor visitor);
 
@@ -1313,141 +1364,17 @@
 /// analysis testing.  Methods in this class may be used to create more complex
 /// expressions based on this one.
 abstract class Expression extends Node
-    with ProtoStatement<Expression>, ProtoCollectionElement<Expression> {
+    with
+        ProtoStatement<Expression>,
+        ProtoCollectionElement<Expression>,
+        ProtoExpression {
   Expression({required super.location}) : super._();
 
   @override
-  CollectionElement get asCollectionElement =>
-      ExpressionCollectionElement(this, location: location);
-
-  @override
-  Statement get asStatement =>
-      new ExpressionStatement._(this, location: location);
-
-  /// If `this` is an expression `x`, creates the expression `x!`.
-  Expression get nonNullAssert =>
-      new NonNullAssert._(this, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `!x`.
-  Expression get not => new Not._(this, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `(x)`.
-  Expression get parenthesized =>
-      new ParenthesizedExpression._(this, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `x && other`.
-  Expression and(Expression other) =>
-      new Logical._(this, other, isAnd: true, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `x as typeStr`.
-  Expression as_(String typeStr) =>
-      new As._(this, Type(typeStr), location: computeLocation());
-
-  /// If `this` is an expression `x`, creates a cascade expression with `x` as
-  /// the target, and [sections] as the cascade sections. [isNullAware]
-  /// indicates whether this is a null-aware cascade.
-  ///
-  /// Since each cascade section needs to implicitly refer to the target of the
-  /// cascade, the caller should pass in a closure for each cascade section; the
-  /// closures will be immediately invoked, passing in a [CascadePlaceholder]
-  /// pseudo-expression representing the implicit reference to the cascade
-  /// target.
-  Expression cascade(List<Expression Function(CascadePlaceholder)> sections,
-      {bool isNullAware = false}) {
-    var location = computeLocation();
-    return Cascade._(
-        this,
-        [
-          for (var section in sections)
-            section(CascadePlaceholder._(location: location))
-        ],
-        isNullAware: isNullAware,
-        location: location);
-  }
-
-  /// Wraps `this` in such a way that, when the test is run, it will verify that
-  /// the context provided when analyzing the expression matches
-  /// [expectedContext].
-  Expression checkContext(String expectedContext) =>
-      CheckExpressionContext._(this, expectedContext,
-          location: computeLocation());
-
-  /// Wraps `this` in such a way that, when the test is run, it will verify that
-  /// the IR produced matches [expectedIR].
-  @override
-  Expression checkIR(String expectedIR) =>
-      CheckExpressionIR._(this, expectedIR, location: computeLocation());
-
-  /// Creates an [Expression] that, when analyzed, will behave the same as
-  /// `this`, but after visiting it, will verify that the type of the expression
-  /// was [expectedType].
-  Expression checkType(String expectedType) =>
-      new CheckExpressionType(this, expectedType, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression
-  /// `x ? ifTrue : ifFalse`.
-  Expression conditional(Expression ifTrue, Expression ifFalse) =>
-      new Conditional._(this, ifTrue, ifFalse, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `x == other`.
-  Expression eq(Expression other) =>
-      new Equal._(this, other, false, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `x ?? other`.
-  Expression ifNull(Expression other) =>
-      new IfNull._(this, other, location: computeLocation());
-
-  /// Creates a [Statement] that, when analyzed, will analyze `this`, supplying
-  /// a context type of [context].
-  Statement inContext(String context) =>
-      ExpressionInContext._(this, Type(context), location: computeLocation());
-
-  /// If `this` is an expression `x`, creates a method invocation with `x` as
-  /// the target, [name] as the method name, and [arguments] as the method
-  /// arguments. Named arguments are not supported.
-  Expression invokeMethod(String name, List<Expression> arguments) =>
-      new InvokeMethod._(this, name, arguments, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `x is typeStr`.
-  ///
-  /// With [isInverted] set to `true`, creates the expression `x is! typeStr`.
-  Expression is_(String typeStr, {bool isInverted = false}) =>
-      new Is._(this, Type(typeStr), isInverted, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `x is! typeStr`.
-  Expression isNot(String typeStr) =>
-      Is._(this, Type(typeStr), true, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `x != other`.
-  Expression notEq(Expression other) =>
-      Equal._(this, other, true, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `x?.other`.
-  ///
-  /// Note that in the real Dart language, the RHS of a null aware access isn't
-  /// strictly speaking an expression.  However for flow analysis it suffices to
-  /// model it as an expression.
-  Expression nullAwareAccess(Expression other, {bool isCascaded = false}) =>
-      NullAwareAccess._(this, other, isCascaded, location: computeLocation());
-
-  /// If `this` is an expression `x`, creates the expression `x || other`.
-  Expression or(Expression other) =>
-      new Logical._(this, other, isAnd: false, location: computeLocation());
+  Expression asExpression({required String location}) => this;
 
   void preVisit(PreVisitor visitor);
 
-  /// If `this` is an expression `x`, creates the L-value `x.name`.
-  PromotableLValue property(String name) =>
-      new Property._(this, name, location: computeLocation());
-
-  /// 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
-  /// test that flow analysis is in the correct state after an expression is
-  /// visited.
-  Expression thenStmt(ProtoStatement stmt) =>
-      new WrappedExpression._(null, this, stmt.asStatement,
-          location: computeLocation());
-
   ExpressionTypeAnalysisResult<Type> visit(Harness h, Type context);
 }
 
@@ -2494,8 +2421,11 @@
   void preVisit(PreVisitor visitor, {_LValueDisposition disposition});
 
   /// Creates an expression representing a write to this L-value.
-  Expression write(Expression? value) =>
-      new Write(this, value, location: computeLocation());
+  Expression write(ProtoExpression? value) {
+    var location = computeLocation();
+    return new Write(this, value?.asExpression(location: location),
+        location: location);
+  }
 
   void _visitWrite(Harness h, Expression assignmentExpression, Type writtenType,
       Expression? rhs);
@@ -3198,8 +3128,11 @@
       new CastPattern(this, Type(type), location: computeLocation());
 
   /// Creates a pattern assignment expression assigning [rhs] to this pattern.
-  Expression assign(Expression rhs) =>
-      PatternAssignment._(this, rhs, location: computeLocation());
+  Expression assign(ProtoExpression rhs) {
+    var location = computeLocation();
+    return PatternAssignment._(this, rhs.asExpression(location: location),
+        location: location);
+  }
 
   Type computeSchema(Harness h);
 
@@ -3219,10 +3152,10 @@
 
   void visit(Harness h, SharedMatchContext context);
 
-  GuardedPattern when(Expression? guard) {
+  GuardedPattern when(ProtoExpression? guard) {
     return GuardedPattern._(
       pattern: this,
-      guard: guard,
+      guard: guard?.asExpression(location: location),
       location: location,
     );
   }
@@ -3457,8 +3390,12 @@
     );
   }
 
-  ExpressionCase thenExpr(Expression body) =>
-      ExpressionCase._(_asGuardedPattern, body, location: computeLocation());
+  ExpressionCase thenExpr(ProtoExpression body) {
+    var location = computeLocation();
+    return ExpressionCase._(
+        _asGuardedPattern, body.asExpression(location: location),
+        location: location);
+  }
 }
 
 /// Data structure holding information needed during the "pre-visit" phase of
@@ -3543,11 +3480,11 @@
   /// [CollectionElement], it is returned unchanged. If it's an [Expression],
   /// it's converted into a collection element.
   ///
-  /// In general, tests shouldn't need to call this getter directly; instead
+  /// In general, tests shouldn't need to call this method directly; instead
   /// they should simply be able to use either an [Expression] or some other
   /// [CollectionElement] in a context where a [CollectionElement] is expected,
   /// and the test infrastructure will call this getter as needed.
-  CollectionElement get asCollectionElement;
+  CollectionElement asCollectionElement({required String location});
 
   /// Wraps `this` in such a way that, when the test is run, it will verify that
   /// the IR produced matches [expectedIR].
@@ -3555,10 +3492,244 @@
 
   /// Creates a [Statement] that, when analyzed, will analyze `this`, supplying
   /// [keyType] and [valueType] as the context (for `Map` literals).
-  Statement inContextMapEntry(String keyType, String valueType) =>
-      CollectionElementInContext(asCollectionElement,
-          CollectionElementContextMapEntry._(keyType, valueType),
-          location: computeLocation());
+  Statement inContextMapEntry(String keyType, String valueType) {
+    var location = computeLocation();
+    return CollectionElementInContext(asCollectionElement(location: location),
+        CollectionElementContextMapEntry._(keyType, valueType),
+        location: location);
+  }
+}
+
+/// Common functionality shared by constructs that can be used where an
+/// expression is expected, in in the pseudo-Dart language used for flow
+/// analysis testing.
+///
+/// The reason this mixin is distinct from the [Expression] class is because
+/// both [Expression]s and [Var]s can be used where a statement is expected
+/// (because a [Var] in an expression context simply becomes a read of the
+/// variable).
+mixin ProtoExpression
+    implements ProtoStatement<Expression>, ProtoCollectionElement<Expression> {
+  /// If `this` is an expression `x`, creates the expression `x!`.
+  Expression get nonNullAssert {
+    var location = computeLocation();
+    return new NonNullAssert._(asExpression(location: location),
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `!x`.
+  Expression get not {
+    var location = computeLocation();
+    return new Not._(asExpression(location: location), location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `(x)`.
+  Expression get parenthesized {
+    var location = computeLocation();
+    return new ParenthesizedExpression._(asExpression(location: location),
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `x && other`.
+  Expression and(ProtoExpression other) {
+    var location = computeLocation();
+    return new Logical._(asExpression(location: location),
+        other.asExpression(location: location),
+        isAnd: true, location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `x as typeStr`.
+  Expression as_(String typeStr) {
+    var location = computeLocation();
+    return new As._(asExpression(location: location), Type(typeStr),
+        location: location);
+  }
+
+  @override
+  CollectionElement asCollectionElement({required String location}) =>
+      ExpressionCollectionElement(asExpression(location: location),
+          location: location);
+
+  /// Converts `this` to an [Expression]. If it's already an [Expression], it is
+  /// returned unchanged. If it's something else (e.g. a [Var]), it's converted
+  /// into an [Expression].
+  ///
+  /// In general, tests shouldn't need to call this method directly; instead
+  /// they should simply be able to use either anything implementing the
+  /// [ProtoExpression] interface in a context where an [Expression] is
+  /// expected, and the test infrastructure will call this getter as needed.
+  Expression asExpression({required String location});
+
+  @override
+  Statement asStatement({required String location}) =>
+      new ExpressionStatement._(asExpression(location: location),
+          location: location);
+
+  /// If `this` is an expression `x`, creates a cascade expression with `x` as
+  /// the target, and [sections] as the cascade sections. [isNullAware]
+  /// indicates whether this is a null-aware cascade.
+  ///
+  /// Since each cascade section needs to implicitly refer to the target of the
+  /// cascade, the caller should pass in a closure for each cascade section; the
+  /// closures will be immediately invoked, passing in a [CascadePlaceholder]
+  /// pseudo-expression representing the implicit reference to the cascade
+  /// target.
+  Expression cascade(
+      List<ProtoExpression Function(CascadePlaceholder)> sections,
+      {bool isNullAware = false}) {
+    var location = computeLocation();
+    return Cascade._(
+        asExpression(location: location),
+        [
+          for (var section in sections)
+            section(CascadePlaceholder._(location: location))
+                .asExpression(location: location)
+        ],
+        isNullAware: isNullAware,
+        location: location);
+  }
+
+  /// Wraps `this` in such a way that, when the test is run, it will verify that
+  /// the context provided when analyzing the expression matches
+  /// [expectedContext].
+  Expression checkContext(String expectedContext) {
+    var location = computeLocation();
+    return CheckExpressionContext._(
+        asExpression(location: location), expectedContext,
+        location: location);
+  }
+
+  /// Wraps `this` in such a way that, when the test is run, it will verify that
+  /// the IR produced matches [expectedIR].
+  @override
+  Expression checkIR(String expectedIR) {
+    var location = computeLocation();
+    return CheckExpressionIR._(asExpression(location: location), expectedIR,
+        location: location);
+  }
+
+  /// Creates an [Expression] that, when analyzed, will behave the same as
+  /// `this`, but after visiting it, will verify that the type of the expression
+  /// was [expectedType].
+  Expression checkType(String expectedType) {
+    var location = computeLocation();
+    return new CheckExpressionType(
+        asExpression(location: location), expectedType,
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression
+  /// `x ? ifTrue : ifFalse`.
+  Expression conditional(ProtoExpression ifTrue, ProtoExpression ifFalse) {
+    var location = computeLocation();
+    return new Conditional._(
+        asExpression(location: location),
+        ifTrue.asExpression(location: location),
+        ifFalse.asExpression(location: location),
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `x == other`.
+  Expression eq(ProtoExpression other) {
+    var location = computeLocation();
+    return new Equal._(asExpression(location: location),
+        other.asExpression(location: location), false,
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `x ?? other`.
+  Expression ifNull(ProtoExpression other) {
+    var location = computeLocation();
+    return new IfNull._(asExpression(location: location),
+        other.asExpression(location: location),
+        location: location);
+  }
+
+  /// Creates a [Statement] that, when analyzed, will analyze `this`, supplying
+  /// a context type of [context].
+  Statement inContext(String context) {
+    var location = computeLocation();
+    return ExpressionInContext._(
+        asExpression(location: location), Type(context),
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates a method invocation with `x` as
+  /// the target, [name] as the method name, and [arguments] as the method
+  /// arguments. Named arguments are not supported.
+  Expression invokeMethod(String name, List<ProtoExpression> arguments) {
+    var location = computeLocation();
+    return new InvokeMethod._(
+        asExpression(location: location),
+        name,
+        [
+          for (var argument in arguments)
+            argument.asExpression(location: location)
+        ],
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `x is typeStr`.
+  ///
+  /// With [isInverted] set to `true`, creates the expression `x is! typeStr`.
+  Expression is_(String typeStr, {bool isInverted = false}) {
+    var location = computeLocation();
+    return new Is._(asExpression(location: location), Type(typeStr), isInverted,
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `x is! typeStr`.
+  Expression isNot(String typeStr) {
+    var location = computeLocation();
+    return Is._(asExpression(location: location), Type(typeStr), true,
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `x != other`.
+  Expression notEq(ProtoExpression other) {
+    var location = computeLocation();
+    return Equal._(asExpression(location: location),
+        other.asExpression(location: location), true,
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `x?.other`.
+  ///
+  /// Note that in the real Dart language, the RHS of a null aware access isn't
+  /// strictly speaking an expression.  However for flow analysis it suffices to
+  /// model it as an expression.
+  Expression nullAwareAccess(ProtoExpression other, {bool isCascaded = false}) {
+    var location = computeLocation();
+    return NullAwareAccess._(asExpression(location: location),
+        other.asExpression(location: location), isCascaded,
+        location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the expression `x || other`.
+  Expression or(ProtoExpression other) {
+    var location = computeLocation();
+    return new Logical._(asExpression(location: location),
+        other.asExpression(location: location),
+        isAnd: false, location: location);
+  }
+
+  /// If `this` is an expression `x`, creates the L-value `x.name`.
+  PromotableLValue property(String name) {
+    var location = computeLocation();
+    return new Property._(asExpression(location: location), name,
+        location: location);
+  }
+
+  /// 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
+  /// test that flow analysis is in the correct state after an expression is
+  /// visited.
+  Expression thenStmt(ProtoStatement stmt) {
+    var location = computeLocation();
+    return new WrappedExpression._(null, asExpression(location: location),
+        stmt.asStatement(location: location),
+        location: location);
+  }
 }
 
 /// Common functionality shared by constructs that can be used where a statement
@@ -3573,11 +3744,11 @@
   /// returned unchanged. If it's an [Expression], it's converted into an
   /// expression statement.
   ///
-  /// In general, tests shouldn't need to call this getter directly; instead
+  /// In general, tests shouldn't need to call this method directly; instead
   /// they should simply be able to use either a [Statement] or an [Expressions]
   /// in a context where a statement is expected, and the test infrastructure
   /// will call this getter as needed.
-  Statement get asStatement;
+  Statement asStatement({required String location});
 
   /// Wraps `this` in such a way that, when the test is run, it will verify that
   /// the IR produced matches [expectedIR].
@@ -3769,11 +3940,14 @@
   Statement({required super.location}) : super._();
 
   @override
-  Statement get asStatement => this;
+  Statement asStatement({required String location}) => this;
 
   @override
-  Statement checkIR(String expectedIR) =>
-      CheckStatementIR._(asStatement, expectedIR, location: computeLocation());
+  Statement checkIR(String expectedIR) {
+    var location = computeLocation();
+    return CheckStatementIR._(asStatement(location: location), expectedIR,
+        location: location);
+  }
 
   void preVisit(PreVisitor visitor);
 
@@ -3835,8 +4009,11 @@
     );
   }
 
-  ExpressionCase thenExpr(Expression body) =>
-      ExpressionCase._(null, body, location: computeLocation());
+  ExpressionCase thenExpr(ProtoExpression body) {
+    var location = computeLocation();
+    return ExpressionCase._(null, body.asExpression(location: location),
+        location: location);
+  }
 }
 
 class SwitchHeadCase extends SwitchHead {
@@ -4160,7 +4337,12 @@
 
 /// Representation of a local variable in the pseudo-Dart language used for flow
 /// analysis testing.
-class Var extends Node implements Promotable {
+class Var extends Node
+    with
+        ProtoStatement<Expression>,
+        ProtoCollectionElement<Expression>,
+        ProtoExpression
+    implements Promotable {
   final String name;
   bool isFinal;
 
@@ -4178,10 +4360,6 @@
       : identity = identity ?? name,
         super._(location: location ?? computeLocation());
 
-  /// Creates an L-value representing a reference to this variable.
-  LValue get expr =>
-      new VariableReference._(this, null, location: computeLocation());
-
   JoinedPatternVariableInconsistency get inconsistency {
     return JoinedPatternVariableInconsistency.none;
   }
@@ -4205,6 +4383,10 @@
     _type = value;
   }
 
+  @override
+  LValue asExpression({required String location}) =>
+      new VariableReference._(this, null, location: location);
+
   Pattern pattern({String? type, String? expectInferredType}) =>
       new VariablePattern._(
           type == null ? null : Type(type), this, expectInferredType,
@@ -4222,10 +4404,10 @@
   String toString() => 'var $name';
 
   /// Creates an expression representing a write to this variable.
-  Expression write(Expression? value) {
+  Expression write(ProtoExpression? value) {
     var location = computeLocation();
-    return new Write(
-        new VariableReference._(this, null, location: location), value,
+    return new Write(new VariableReference._(this, null, location: location),
+        value?.asExpression(location: location),
         location: location);
   }
 
diff --git a/pkg/_fe_analyzer_shared/test/type_inference/type_inference_test.dart b/pkg/_fe_analyzer_shared/test/type_inference/type_inference_test.dart
index e8f1a30..86c1519 100644
--- a/pkg/_fe_analyzer_shared/test/type_inference/type_inference_test.dart
+++ b/pkg/_fe_analyzer_shared/test/type_inference/type_inference_test.dart
@@ -91,7 +91,7 @@
           listLiteral(elementType: 'int', [
             ifCaseElement(
               expr('Object'),
-              x.pattern().when(x.expr.eq(intLiteral(0))),
+              x.pattern().when(x.eq(intLiteral(0))),
               intLiteral(1).checkContext('int'),
             ).checkIR('if(expression: expr(Object), pattern: '
                 'varPattern(x, matchedType: Object, staticType: Object), '
@@ -390,10 +390,7 @@
           switchExpr(expr('int'), [
             i
                 .pattern()
-                .when(i.expr
-                    .checkType('int')
-                    .eq(expr('num'))
-                    .checkContext('bool'))
+                .when(i.checkType('int').eq(expr('num')).checkContext('bool'))
                 .thenExpr(expr('String')),
           ]).checkIR('switchExpr(expr(int), case(head(varPattern(i, '
               'matchedType: int, staticType: int), ==(i, expr(num)), '
@@ -566,7 +563,7 @@
         h.run([
           ifCase(
             expr('num'),
-            x.pattern(type: 'int').when(x.expr.eq(intLiteral(0))),
+            x.pattern(type: 'int').when(x.eq(intLiteral(0))),
             [],
           ).checkIR('ifCase(expr(num), '
               'varPattern(x, matchedType: num, staticType: int), variables(x), '
@@ -811,10 +808,7 @@
             [
               i
                   .pattern()
-                  .when(i.expr
-                      .checkType('int')
-                      .eq(expr('num'))
-                      .checkContext('bool'))
+                  .when(i.checkType('int').eq(expr('num')).checkContext('bool'))
                   .then([
                 break_(),
               ]),