Begin reworking ResolutionStorer API to look more like the Factory class.

This CL makes the following changes:

- Removes the type parameters from the ResolutionStorer interface;
  they remain in the implementation (which is now called
  _ResolutionStorer).  In a follow-up CL I will add type parameters to
  ResolutionStorer to match those expected by Factory.  In the long
  term, once the types have settled down, I'll fuse ResolutionStorer
  and _ResolutionStorer back together and make the types more
  concrete.

- Removes the "...Enter" calls from ResolutionStorer and
  TypeInferenceListener.  Now all the information needed by the
  analyzer is passed in the "...Exit" methods (and the word "Exit" has
  been dropped from the method names).  As a consequence,
  _ResolutionStorer no longer needs to use a stack of function
  pointers to defer work from the "...Enter" to the "...Exit" calls.

- Removes the TypeInferenceBase class and moves the base class methods
  into ResolutionStorer.  This makes TypeInferenceListener a strictly
  abstract interface class, which is easier to reason about.

- Adds a KernelTypeInferenceListener class, which implements
  TypeInferenceListener and does nothing.  This is used during top
  level type inference, where we don't need to report resolution
  information to the analyzer.  Eventually this will be replaced with
  ToplevelInferenceFactory.

In a follow-up CL I will add additional parameters to the
ResolutionStorer methods so that they match the Factory method
signatures exactly, and add an "implements" clause to keep them in
sync.

Change-Id: I908b643293d051474dfb4ff24430430bc1572672
Reviewed-on: https://dart-review.googlesource.com/61403
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart b/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart
index ff4bb12..a1845c1 100644
--- a/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart
@@ -379,7 +379,7 @@
       ModifierBuilder builder, Scope memberScope, bool isInstanceMember,
       [Scope formalParameterScope,
       TypeInferenceListener<int, int, Node, int> listener]) {
-    ResolutionStorer<int, int, Node, int> storer;
+    ResolutionStorer storer;
     var fileResolutions = _resolutions[builder.fileUri];
     if (fileResolutions == null) {
       fileResolutions = <CollectedResolution>[];
@@ -387,7 +387,7 @@
     }
     var resolution = new CollectedResolution();
     fileResolutions.add(resolution);
-    storer = new ResolutionStorer<int, int, Node, int>(resolution.kernelData);
+    storer = new ResolutionStorer(resolution.kernelData);
     return super.createListener(
         builder, memberScope, isInstanceMember, formalParameterScope, storer);
   }
diff --git a/pkg/analyzer/lib/src/fasta/resolution_storer.dart b/pkg/analyzer/lib/src/fasta/resolution_storer.dart
index ebdd2cc..3713e55 100644
--- a/pkg/analyzer/lib/src/fasta/resolution_storer.dart
+++ b/pkg/analyzer/lib/src/fasta/resolution_storer.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/fasta/resolution_applier.dart';
+import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
 import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/type_algebra.dart';
@@ -38,15 +39,22 @@
 
 /// Type inference listener that records inferred types for later use by
 /// [ResolutionApplier].
-class ResolutionStorer<Location, Declaration, Reference, PrefixInfo>
-    extends TypeInferenceListener<Location, Declaration, Reference,
-        PrefixInfo> {
+class ResolutionStorer extends _ResolutionStorer<int, int, Node, int> {
+  ResolutionStorer(Map<int, ResolutionData<DartType, int, Node, int>> data)
+      : super(data);
+}
+
+/// Implementation of [ResolutionStorer], with types parameterized to avoid
+/// accidentally peeking into kernel internals.
+///
+/// TODO(paulberry): when the time is right, fuse this with [ResolutionStorer].
+class _ResolutionStorer<Location, Declaration, Reference, PrefixInfo>
+    implements
+        TypeInferenceListener<Location, Declaration, Reference, PrefixInfo> {
   final Map<Location,
       ResolutionData<DartType, Declaration, Reference, PrefixInfo>> _data;
 
-  final _stack = <Function>[];
-
-  ResolutionStorer(this._data);
+  _ResolutionStorer(this._data);
 
   void _store(Location location,
       {List<DartType> argumentTypes,
@@ -85,12 +93,36 @@
   }
 
   @override
-  void asExpressionExit(Location location, DartType inferredType) {
+  void asExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType) {
     _store(location, literalType: inferredType, inferredType: inferredType);
   }
 
   @override
-  void cascadeExpressionExit(Location location, DartType inferredType) {
+  void assertInitializer(InitializerJudgment judgment, Location location) {}
+
+  @override
+  void assertStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void awaitExpression(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("awaitExpression", location, inferredType);
+
+  @override
+  void block(StatementJudgment judgment, Location location) {}
+
+  @override
+  void boolLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("boolLiteral", location, inferredType);
+
+  @override
+  void breakStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void cascadeExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType) {
     // Overridden so that the type of the expression will not be recorded. We
     // don't need to record the type because the type is always the same as the
     // type of the target, and we don't have the appropriate offset so we can't
@@ -98,7 +130,8 @@
   }
 
   @override
-  void catchStatementEnter(
+  void catchStatement(
+      Catch judgment,
       Location location,
       DartType guardType,
       Location exceptionLocation,
@@ -117,107 +150,161 @@
   }
 
   @override
-  void constructorInvocationEnter(Location location, DartType typeContext) {
-    _push((Reference expressionTarget, DartType inferredType) {
-      // A class reference may have already been stored at this location by
-      // storeClassReference.  We want to replace it with a constructor
-      // reference.
-      _unstore(location);
-      _store(location, inferredType: inferredType, reference: expressionTarget);
-    });
+  void conditionalExpression(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("conditionalExpression", location, inferredType);
+
+  @override
+  void constructorInvocation(ExpressionJudgment judgment, Location location,
+      Reference expressionTarget, DartType inferredType) {
+    // A class reference may have already been stored at this location by
+    // storeClassReference.  We want to replace it with a constructor
+    // reference.
+    _unstore(location);
+    _store(location, inferredType: inferredType, reference: expressionTarget);
   }
 
   @override
-  void constructorInvocationExit(
-      Location location, Reference expressionTarget, DartType inferredType) {
-    _pop()(expressionTarget, inferredType);
-  }
+  void continueSwitchStatement(StatementJudgment judgment, Location location) {}
 
   @override
-  void fieldInitializerEnter(Location location, Reference initializerField) {
+  void deferredCheck(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("deferredCheck", location, inferredType);
+
+  @override
+  void doStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void doubleLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("doubleLiteral", location, inferredType);
+
+  @override
+  void expressionStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void fieldInitializer(InitializerJudgment judgment, Location location,
+      Reference initializerField) {
     _store(location, reference: initializerField);
   }
 
-  void finished() {
-    assert(_stack.isEmpty);
-  }
-
   @override
-  void forInStatementEnter(
+  void forInStatement(
+      StatementJudgment judgment,
       Location location,
       Location variableLocation,
+      DartType variableType,
       Location writeLocation,
       DartType writeType,
       Declaration writeVariable,
       Reference writeTarget) {
-    _push((DartType variableType) {
-      if (variableLocation != null) {
-        _store(variableLocation, inferredType: variableType);
+    if (variableLocation != null) {
+      _store(variableLocation, inferredType: variableType);
+    } else {
+      if (writeVariable != null) {
+        _store(writeLocation,
+            declaration: writeVariable, inferredType: writeType);
       } else {
-        if (writeVariable != null) {
-          _store(writeLocation,
-              declaration: writeVariable, inferredType: writeType);
-        } else {
-          _store(writeLocation,
-              reference: writeTarget,
-              isWriteReference: true,
-              writeContext: writeType);
-        }
+        _store(writeLocation,
+            reference: writeTarget,
+            isWriteReference: true,
+            writeContext: writeType);
       }
-    });
+    }
   }
 
   @override
-  void forInStatementExit(
-      Location location, bool variablePresent, DartType variableType) {
-    _pop()(variableType);
+  void forStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void functionDeclaration(StatementJudgment judgment, Location location,
+      FunctionType inferredType) {
+    _store(location, inferredType: inferredType);
   }
 
   @override
-  void genericExpressionEnter(
-      String expressionType, Location location, DartType typeContext) {
-    super.genericExpressionEnter(expressionType, location, typeContext);
-  }
+  void functionExpression(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("functionExpression", location, inferredType);
 
-  @override
-  void genericExpressionExit(
+  void genericExpression(
       String expressionType, Location location, DartType inferredType) {
     _store(location, inferredType: inferredType);
-    super.genericExpressionExit(expressionType, location, inferredType);
   }
 
   @override
-  void functionDeclarationExit(Location location, FunctionType inferredType) {
-    _store(location, inferredType: inferredType);
-  }
+  void ifNull(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression('ifNull', location, inferredType);
 
   @override
-  void nullLiteralExit(
-      Location location, bool isSynthetic, DartType inferredType) {
+  void ifStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void intLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("intLiteral", location, inferredType);
+
+  @override
+  void invalidInitializer(InitializerJudgment judgment, Location location) {}
+
+  @override
+  void labeledStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void listLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("listLiteral", location, inferredType);
+
+  @override
+  void logicalExpression(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("logicalExpression", location, inferredType);
+
+  @override
+  void mapLiteral(ExpressionJudgment judgment, Location location,
+          DartType typeContext) =>
+      genericExpression("mapLiteral", location, typeContext);
+
+  @override
+  void namedFunctionExpression(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("namedFunctionExpression", location, inferredType);
+
+  @override
+  void not(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("not", location, inferredType);
+
+  @override
+  void nullLiteral(ExpressionJudgment judgment, Location location,
+      bool isSynthetic, DartType inferredType) {
     if (isSynthetic) return null;
-    super.nullLiteralExit(location, isSynthetic, inferredType);
+    genericExpression("nullLiteral", location, inferredType);
   }
 
   @override
-  void indexAssignExit(Location location, Reference writeMember,
-      Reference combiner, DartType inferredType) {
+  void indexAssign(ExpressionJudgment judgment, Location location,
+      Reference writeMember, Reference combiner, DartType inferredType) {
     _store(location,
         reference: writeMember, inferredType: inferredType, combiner: combiner);
   }
 
   @override
-  void isExpressionExit(
-      Location location, DartType testedType, DartType inferredType) {
+  void isExpression(ExpressionJudgment judgment, Location location,
+      DartType testedType, DartType inferredType) {
     _store(location, literalType: testedType, inferredType: inferredType);
   }
 
-  void isNotExpressionExit(
-      Location location, DartType type, DartType inferredType) {
+  void isNotExpression(ExpressionJudgment judgment, Location location,
+      DartType type, DartType inferredType) {
     _store(location, literalType: type, inferredType: inferredType);
   }
 
   @override
-  void methodInvocationExit(
+  void methodInvocation(
+      ExpressionJudgment judgment,
       Location resultOffset,
       List<DartType> argumentsTypes,
       bool isImplicitCall,
@@ -235,12 +322,11 @@
         invokeType: invokeType,
         isImplicitCall: isImplicitCall,
         reference: interfaceMember);
-
-    super.genericExpressionExit("methodInvocation", resultOffset, inferredType);
   }
 
   @override
-  void methodInvocationExitCall(
+  void methodInvocationCall(
+      ExpressionJudgment judgment,
       Location resultOffset,
       List<DartType> argumentsTypes,
       bool isImplicitCall,
@@ -256,13 +342,16 @@
         argumentTypes: argumentsTypes,
         invokeType: invokeType,
         isImplicitCall: isImplicitCall);
-
-    super.genericExpressionExit("methodInvocation", resultOffset, inferredType);
   }
 
   @override
-  void propertyAssignExit(Location location, Reference writeMember,
-      DartType writeContext, Reference combiner, DartType inferredType) {
+  void propertyAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      Reference writeMember,
+      DartType writeContext,
+      Reference combiner,
+      DartType inferredType) {
     _store(location,
         isWriteReference: true,
         reference: writeMember,
@@ -272,110 +361,128 @@
   }
 
   @override
-  void propertyGetExit(
-      Location location, Reference member, DartType inferredType) {
+  void propertySet(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("propertySet", location, inferredType);
+
+  @override
+  void propertyGet(ExpressionJudgment judgment, Location location,
+      Reference member, DartType inferredType) {
     _store(location, reference: member, inferredType: inferredType);
   }
 
   @override
-  void propertyGetExitCall(Location location, DartType inferredType) {
+  void propertyGetCall(
+      ExpressionJudgment judgment, Location location, DartType inferredType) {
     _store(location, isExplicitCall: true);
   }
 
   @override
-  void redirectingInitializerEnter(
-      Location location, Reference initializerTarget) {
+  void redirectingInitializer(InitializerJudgment judgment, Location location,
+      Reference initializerTarget) {
     _store(location, reference: initializerTarget);
   }
 
   @override
-  void staticAssignEnter(Location location, DartType typeContext) {
-    _push((Reference writeMember, DartType writeContext, Reference combiner,
-        DartType inferredType) {
-      _store(location,
-          reference: writeMember,
-          isWriteReference: true,
-          writeContext: writeContext,
-          combiner: combiner,
-          inferredType: inferredType);
-    });
+  void rethrow_(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression('rethrow', location, inferredType);
+
+  @override
+  void returnStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void staticAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      Reference writeMember,
+      DartType writeContext,
+      Reference combiner,
+      DartType inferredType) {
+    _store(location,
+        reference: writeMember,
+        isWriteReference: true,
+        writeContext: writeContext,
+        combiner: combiner,
+        inferredType: inferredType);
   }
 
   @override
-  void staticAssignExit(Location location, Reference writeMember,
-      DartType writeContext, Reference combiner, DartType inferredType) {
-    _pop()(writeMember, writeContext, combiner, inferredType);
+  void staticGet(ExpressionJudgment judgment, Location location,
+      Reference expressionTarget, DartType inferredType) {
+    _store(location, reference: expressionTarget, inferredType: inferredType);
   }
 
   @override
-  void staticGetEnter(Location location, DartType typeContext) {
-    _push(
-        (Location location, Reference expressionTarget, DartType inferredType) {
-      _store(location, reference: expressionTarget, inferredType: inferredType);
-    });
-  }
-
-  @override
-  void staticGetExit(
-      Location location, Reference expressionTarget, DartType inferredType) {
-    _pop()(location, expressionTarget, inferredType);
-  }
-
-  @override
-  void staticInvocationEnter(Location location,
-      Location expressionArgumentsLocation, DartType typeContext) {
-    _push((Reference expressionTarget,
-        List<DartType> expressionArgumentsTypes,
-        FunctionType calleeType,
-        Substitution substitution,
-        DartType inferredType) {
-      FunctionType invokeType = substitution == null
-          ? calleeType
-          : substitution.substituteType(calleeType.withoutTypeParameters);
-      _store(expressionArgumentsLocation,
-          invokeType: invokeType,
-          argumentTypes: expressionArgumentsTypes,
-          reference: expressionTarget,
-          inferredType: inferredType);
-    });
-  }
-
-  @override
-  void staticInvocationExit(
+  void staticInvocation(
+      ExpressionJudgment judgment,
       Location location,
       Reference expressionTarget,
       List<DartType> expressionArgumentsTypes,
       FunctionType calleeType,
       Substitution substitution,
       DartType inferredType) {
-    _pop()(expressionTarget, expressionArgumentsTypes, calleeType, substitution,
-        inferredType);
+    FunctionType invokeType = substitution == null
+        ? calleeType
+        : substitution.substituteType(calleeType.withoutTypeParameters);
+    _store(location,
+        invokeType: invokeType,
+        argumentTypes: expressionArgumentsTypes,
+        reference: expressionTarget,
+        inferredType: inferredType);
   }
 
   @override
-  void stringConcatenationExit(Location location, DartType inferredType) {
+  void stringConcatenation(
+      ExpressionJudgment judgment, Location location, DartType inferredType) {
     // We don't need the type - we already know that it is String.
     // Moreover, the file offset for StringConcatenation is `-1`.
   }
 
   @override
-  void thisExpressionExit(Location location, DartType inferredType) {}
+  void stringLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("StringLiteral", location, inferredType);
 
   @override
-  void typeLiteralEnter(Location location, DartType typeContext) {
-    _push((Reference expressionType, DartType inferredType) {
-      _store(location, reference: expressionType, inferredType: inferredType);
-    });
-  }
+  void superInitializer(InitializerJudgment judgment, Location location) {}
 
-  void typeLiteralExit(
-      Location location, Reference expressionType, DartType inferredType) {
-    _pop()(expressionType, inferredType);
+  @override
+  void switchStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void symbolLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("symbolLiteral", location, inferredType);
+
+  @override
+  void thisExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType) {}
+
+  @override
+  void throw_(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression('throw', location, inferredType);
+
+  @override
+  void tryCatch(StatementJudgment judgment, Location location) {}
+
+  @override
+  void tryFinally(StatementJudgment judgment, Location location) {}
+
+  void typeLiteral(ExpressionJudgment judgment, Location location,
+      Reference expressionType, DartType inferredType) {
+    _store(location, reference: expressionType, inferredType: inferredType);
   }
 
   @override
-  void variableAssignExit(Location location, DartType writeContext,
-      Declaration writeVariable, Reference combiner, DartType inferredType) {
+  void variableAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      DartType writeContext,
+      Declaration writeVariable,
+      Reference combiner,
+      DartType inferredType) {
     _store(location,
         declaration: writeVariable,
         isWriteReference: true,
@@ -385,14 +492,14 @@
   }
 
   @override
-  void variableDeclarationExit(
-      Location location, DartType statementType, DartType inferredType) {
+  void variableDeclaration(StatementJudgment judgment, Location location,
+      DartType statementType, DartType inferredType) {
     _store(location, literalType: statementType, inferredType: inferredType);
   }
 
   @override
-  void variableGetExit(Location location, bool isInCascade,
-      Declaration expressionVariable, DartType inferredType) {
+  void variableGet(ExpressionJudgment judgment, Location location,
+      bool isInCascade, Declaration expressionVariable, DartType inferredType) {
     if (isInCascade) {
       return;
     }
@@ -400,13 +507,16 @@
         declaration: expressionVariable, inferredType: inferredType);
   }
 
-  void _push(Function f) {
-    _stack.add(f);
-  }
+  @override
+  void variableSet(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("variableSet", location, inferredType);
 
-  Function _pop() {
-    return _stack.removeLast();
-  }
+  @override
+  void whileStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void yieldStatement(StatementJudgment judgment, Location location) {}
 
   @override
   void storePrefixInfo(Location location, PrefixInfo prefixInfo) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
index 519886d..642fa62 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
@@ -5,7 +5,7 @@
 library fasta.kernel_field_builder;
 
 import 'package:kernel/ast.dart'
-    show DartType, Expression, Field, Name, Node, NullLiteral;
+    show DartType, Expression, Field, Name, NullLiteral;
 
 import '../../base/instrumentation.dart'
     show Instrumentation, InstrumentationValueForType;
@@ -17,7 +17,7 @@
 import '../problems.dart' show internalProblem;
 
 import '../type_inference/type_inference_listener.dart'
-    show TypeInferenceListener;
+    show KernelTypeInferenceListener;
 
 import 'kernel_body_builder.dart' show KernelBodyBuilder;
 
@@ -90,7 +90,7 @@
   @override
   void prepareTopLevelInference() {
     if (!isEligibleForInference) return;
-    var listener = new TypeInferenceListener<int, int, Node, int>();
+    var listener = new KernelTypeInferenceListener();
     var typeInferrer = library.loader.typeInferenceEngine
         .createTopLevelTypeInferrer(
             listener, field.enclosingClass?.thisType, field);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index b532032..a9b13d6 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -168,10 +168,9 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.asExpressionEnter(fileOffset, typeContext);
     inferrer.inferExpression(factory, judgment, const UnknownType(), false);
     inferredType = type;
-    inferrer.listener.asExpressionExit(fileOffset, inferredType);
+    inferrer.listener.asExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -187,9 +186,8 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.assertInitializerEnter(fileOffset);
     inferrer.inferStatement(factory, judgment);
-    inferrer.listener.assertInitializerExit(fileOffset);
+    inferrer.listener.assertInitializer(this, fileOffset);
   }
 }
 
@@ -211,7 +209,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.assertStatementEnter(fileOffset);
     var conditionJudgment = this.conditionJudgment;
     var messageJudgment = this.messageJudgment;
     var expectedType = inferrer.coreTypes.boolClass.rawType;
@@ -223,7 +220,7 @@
       inferrer.inferExpression(
           factory, messageJudgment, const UnknownType(), false);
     }
-    inferrer.listener.assertStatementExit(fileOffset);
+    inferrer.listener.assertStatement(this, fileOffset);
   }
 }
 
@@ -240,7 +237,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.awaitExpressionEnter(fileOffset, typeContext);
     if (!inferrer.typeSchemaEnvironment.isEmptyContext(typeContext)) {
       typeContext = inferrer.wrapFutureOrType(typeContext);
     }
@@ -248,7 +244,7 @@
     inferrer.inferExpression(factory, judgment, typeContext, true);
     inferredType =
         inferrer.typeSchemaEnvironment.unfutureType(judgment.inferredType);
-    inferrer.listener.awaitExpressionExit(fileOffset, inferredType);
+    inferrer.listener.awaitExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -263,11 +259,10 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.blockEnter(fileOffset);
     for (var judgment in judgments) {
       inferrer.inferStatement(factory, judgment);
     }
-    inferrer.listener.blockExit(fileOffset);
+    inferrer.listener.block(this, fileOffset);
   }
 }
 
@@ -282,9 +277,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.boolLiteralEnter(fileOffset, typeContext);
     inferredType = inferrer.coreTypes.boolClass.rawType;
-    inferrer.listener.boolLiteralExit(fileOffset, inferredType);
+    inferrer.listener.boolLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -309,9 +303,8 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.breakStatementEnter(fileOffset);
     // No inference needs to be done.
-    inferrer.listener.breakStatementExit(fileOffset);
+    inferrer.listener.breakStatement(this, fileOffset);
   }
 }
 
@@ -375,7 +368,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.cascadeExpressionEnter(fileOffset, typeContext);
     var lhsType = inferrer.inferExpression(
         factory, variable.initializer, typeContext, true);
     if (inferrer.strongMode) {
@@ -388,7 +380,7 @@
       if (section.body is! Let) break;
       section = section.body;
     }
-    inferrer.listener.cascadeExpressionExit(fileOffset, lhsType);
+    inferrer.listener.cascadeExpression(this, fileOffset, lhsType);
     return lhsType;
   }
 }
@@ -666,7 +658,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.conditionalExpressionEnter(fileOffset, typeContext);
     var conditionJudgment = this.conditionJudgment;
     var thenJudgment = this.thenJudgment;
     var otherwiseJudgment = this.otherwiseJudgment;
@@ -685,7 +676,7 @@
     if (inferrer.strongMode) {
       staticType = inferredType;
     }
-    inferrer.listener.conditionalExpressionExit(fileOffset, inferredType);
+    inferrer.listener.conditionalExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -723,7 +714,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.constructorInvocationEnter(fileOffset, typeContext);
     var library = inferrer.engine.beingInferred[target];
     if (library != null) {
       // There is a cyclic dependency where inferring the types of the
@@ -772,7 +762,7 @@
           noLength);
     }
     inferrer.listener
-        .constructorInvocationExit(fileOffset, target, inferredType);
+        .constructorInvocation(this, fileOffset, target, inferredType);
 
     if (isRedirected(this)) {
       InterfaceType returnType = inferredType;
@@ -821,9 +811,8 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.continueSwitchStatementEnter(fileOffset);
     // No inference needs to be done.
-    inferrer.listener.continueSwitchStatementExit(fileOffset);
+    inferrer.listener.continueSwitchStatement(this, fileOffset);
   }
 }
 
@@ -839,12 +828,11 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.deferredCheckEnter(fileOffset, typeContext);
     // Since the variable is not used in the body we don't need to type infer
     // it.  We can just type infer the body.
     var inferredType =
         inferrer.inferExpression(factory, body, typeContext, true);
-    inferrer.listener.deferredCheckExit(fileOffset, inferredType);
+    inferrer.listener.deferredCheck(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -861,7 +849,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.doStatementEnter(fileOffset);
     var conditionJudgment = this.conditionJudgment;
     inferrer.inferStatement(factory, bodyJudgment);
     var boolType = inferrer.coreTypes.boolClass.rawType;
@@ -869,7 +856,7 @@
         factory, conditionJudgment, boolType, !inferrer.isTopLevel);
     inferrer.ensureAssignable(boolType, conditionJudgment.inferredType,
         condition, condition.fileOffset);
-    inferrer.listener.doStatementExit(fileOffset);
+    inferrer.listener.doStatement(this, fileOffset);
   }
 }
 
@@ -884,9 +871,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.doubleLiteralEnter(fileOffset, typeContext);
     inferredType = inferrer.coreTypes.doubleClass.rawType;
-    inferrer.listener.doubleLiteralExit(fileOffset, inferredType);
+    inferrer.listener.doubleLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -926,9 +912,8 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.expressionStatementEnter(fileOffset);
     inferrer.inferExpression(factory, judgment, const UnknownType(), false);
-    inferrer.listener.expressionStatementExit(fileOffset);
+    inferrer.listener.expressionStatement(this, fileOffset);
   }
 }
 
@@ -966,7 +951,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.constructorInvocationEnter(fileOffset, typeContext);
     var inferredType = inferrer.inferInvocation(
         factory,
         typeContext,
@@ -975,7 +959,7 @@
         computeConstructorReturnType(_initialTarget),
         arguments);
     inferrer.listener
-        .constructorInvocationExit(fileOffset, target, inferredType);
+        .constructorInvocation(this, fileOffset, target, inferredType);
 
     if (isRedirected(this)) {
       InterfaceType returnType = inferredType;
@@ -1052,11 +1036,10 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.fieldInitializerEnter(fileOffset, field);
     var initializerType =
         inferrer.inferExpression(factory, value, field.type, true);
     inferrer.ensureAssignable(field.type, initializerType, value, fileOffset);
-    inferrer.listener.fieldInitializerExit(fileOffset);
+    inferrer.listener.fieldInitializer(this, fileOffset, field);
   }
 }
 
@@ -1101,38 +1084,6 @@
       context = const UnknownType();
     }
     context = inferrer.wrapType(context, iterableClass);
-    if (syntheticWrite is VariableSet) {
-      inferrer.listener.forInStatementEnter(
-          fileOffset,
-          variable?.fileOffset,
-          syntheticWrite.fileOffset,
-          syntheticWrite.variable.type,
-          syntheticWrite.variable.fileOffset,
-          null);
-    } else if (syntheticWrite is PropertySet) {
-      inferrer.listener.forInStatementEnter(
-          fileOffset,
-          variable?.fileOffset,
-          syntheticWrite.fileOffset,
-          syntheticWrite.interfaceTarget?.setterType,
-          null,
-          syntheticWrite.interfaceTarget);
-    } else if (syntheticWrite is StaticSet) {
-      inferrer.listener.forInStatementEnter(
-          fileOffset,
-          variable?.fileOffset,
-          syntheticWrite.fileOffset,
-          syntheticWrite.target.setterType,
-          null,
-          syntheticWrite.target);
-    } else if (syntheticWrite == null ||
-        syntheticWrite is ShadowSyntheticExpression) {
-      inferrer.listener.forInStatementEnter(
-          fileOffset, variable?.fileOffset, null, null, null, null);
-    } else {
-      throw new UnimplementedError(
-          '(${syntheticWrite.runtimeType}) $syntheticWrite');
-    }
     var inferredExpressionType = inferrer.resolveTypeParameter(
         inferrer.inferExpression(
             factory, iterable, context, typeNeeded || typeChecksNeeded));
@@ -1188,8 +1139,44 @@
       }
       syntheticAssignment._replaceWithDesugared();
     }
-    inferrer.listener
-        .forInStatementExit(fileOffset, variable != null, variable?.type);
+    if (syntheticWrite is VariableSet) {
+      inferrer.listener.forInStatement(
+          this,
+          fileOffset,
+          variable?.fileOffset,
+          variable?.type,
+          syntheticWrite.fileOffset,
+          syntheticWrite.variable.type,
+          syntheticWrite.variable.fileOffset,
+          null);
+    } else if (syntheticWrite is PropertySet) {
+      inferrer.listener.forInStatement(
+          this,
+          fileOffset,
+          variable?.fileOffset,
+          variable?.type,
+          syntheticWrite.fileOffset,
+          syntheticWrite.interfaceTarget?.setterType,
+          null,
+          syntheticWrite.interfaceTarget);
+    } else if (syntheticWrite is StaticSet) {
+      inferrer.listener.forInStatement(
+          this,
+          fileOffset,
+          variable?.fileOffset,
+          variable?.type,
+          syntheticWrite.fileOffset,
+          syntheticWrite.target.setterType,
+          null,
+          syntheticWrite.target);
+    } else if (syntheticWrite == null ||
+        syntheticWrite is ShadowSyntheticExpression) {
+      inferrer.listener.forInStatement(this, fileOffset, variable?.fileOffset,
+          variable?.type, null, null, null, null);
+    } else {
+      throw new UnimplementedError(
+          '(${syntheticWrite.runtimeType}) $syntheticWrite');
+    }
   }
 }
 
@@ -1203,7 +1190,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.forStatementEnter(fileOffset);
     for (var variable in variables) {
       inferrer.inferStatement(factory, variable);
     }
@@ -1218,7 +1204,7 @@
       inferrer.inferExpression(factory, update, const UnknownType(), false);
     }
     inferrer.inferStatement(factory, body);
-    inferrer.listener.forStatementExit(fileOffset);
+    inferrer.listener.forStatement(this, fileOffset);
   }
 }
 
@@ -1235,7 +1221,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.functionDeclarationEnter(fileOffset);
     inferrer.inferMetadataKeepingHelper(factory, variable.annotations);
     inferrer.inferLocalFunction(
         factory,
@@ -1246,7 +1231,7 @@
             ? (inferrer.strongMode ? null : const DynamicType())
             : function.returnType);
     var inferredType = variable.type = function.functionType;
-    inferrer.listener.functionDeclarationExit(fileOffset, inferredType);
+    inferrer.listener.functionDeclaration(this, fileOffset, inferredType);
   }
 
   static void setHasImplicitReturnType(
@@ -1267,10 +1252,9 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.functionExpressionEnter(fileOffset, typeContext);
     var inferredType = inferrer.inferLocalFunction(
         factory, function, typeContext, fileOffset, null);
-    inferrer.listener.functionExpressionExit(fileOffset, inferredType);
+    inferrer.listener.functionExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1301,14 +1285,12 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.ifNullEnter(fileOffset, typeContext);
     // To infer `e0 ?? e1` in context K:
     // - Infer e0 in context K to get T0
     var lhsType = inferrer.inferExpression(factory, _lhs, typeContext, true);
     if (inferrer.strongMode) {
       variable.type = lhsType;
     }
-    inferrer.listener.ifNullBeforeRhs(fileOffset);
     // - Let J = T0 if K is `?` else K.
     // - Infer e1 in context J to get T1
     bool useLub = _forceLub || typeContext is UnknownType;
@@ -1324,7 +1306,7 @@
     if (inferrer.strongMode) {
       body.staticType = inferredType;
     }
-    inferrer.listener.ifNullExit(fileOffset, inferredType);
+    inferrer.listener.ifNull(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1344,7 +1326,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.ifStatementEnter(fileOffset);
     var conditionJudgment = this.conditionJudgment;
     var expectedType = inferrer.coreTypes.boolClass.rawType;
     inferrer.inferExpression(
@@ -1355,7 +1336,7 @@
     if (otherwiseJudgment != null) {
       inferrer.inferStatement(factory, otherwiseJudgment);
     }
-    inferrer.listener.ifStatementExit(fileOffset);
+    inferrer.listener.ifStatement(this, fileOffset);
   }
 }
 
@@ -1416,9 +1397,7 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.indexAssignEnter(desugared.fileOffset, typeContext);
     var receiverType = _inferReceiver(inferrer, factory);
-    inferrer.listener.indexAssignAfterReceiver(write.fileOffset, typeContext);
     var writeMember = inferrer.findMethodInvocationMember(receiverType, write);
     // To replicate analyzer behavior, we base type inference on the write
     // member.  TODO(paulberry): would it be better to use the read member
@@ -1472,7 +1451,7 @@
       _storeLetType(inferrer, replacedRead, readType);
     }
     var inferredResult = _inferRhs(inferrer, factory, readType, writeContext);
-    inferrer.listener.indexAssignExit(write.fileOffset, writeMember,
+    inferrer.listener.indexAssign(this, write.fileOffset, writeMember,
         inferredResult.combiner, inferredResult.type);
     _replaceWithDesugared();
     return inferredResult.type;
@@ -1500,9 +1479,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.intLiteralEnter(fileOffset, typeContext);
     inferredType = inferrer.coreTypes.intClass.rawType;
-    inferrer.listener.intLiteralExit(fileOffset, inferredType);
+    inferrer.listener.intLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1516,10 +1494,9 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.invalidInitializerEnter(fileOffset);
     inferrer.inferExpression(
         factory, variable.initializer, const UnknownType(), false);
-    inferrer.listener.invalidInitializerExit(fileOffset);
+    inferrer.listener.invalidInitializer(this, fileOffset);
   }
 }
 
@@ -1536,10 +1513,9 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.isExpressionEnter(fileOffset, typeContext);
     inferrer.inferExpression(factory, judgment, const UnknownType(), false);
     inferredType = inferrer.coreTypes.boolClass.rawType;
-    inferrer.listener.isExpressionExit(fileOffset, type, inferredType);
+    inferrer.listener.isExpression(this, fileOffset, type, inferredType);
     return inferredType;
   }
 }
@@ -1563,11 +1539,10 @@
       DartType typeContext) {
     IsExpression isExpression = this.operand;
 
-    inferrer.listener.isNotExpressionEnter(fileOffset, typeContext);
     inferrer.inferExpression(factory, judgment, const UnknownType(), false);
     inferredType = inferrer.coreTypes.boolClass.rawType;
     inferrer.listener
-        .isNotExpressionExit(fileOffset, isExpression.type, inferredType);
+        .isNotExpression(this, fileOffset, isExpression.type, inferredType);
     return inferredType;
   }
 }
@@ -1583,9 +1558,8 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.labeledStatementEnter(fileOffset);
     inferrer.inferStatement(factory, judgment);
-    inferrer.listener.labeledStatementExit(fileOffset);
+    inferrer.listener.labeledStatement(this, fileOffset);
   }
 }
 
@@ -1607,7 +1581,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.listLiteralEnter(fileOffset, typeContext);
     var listClass = inferrer.coreTypes.listClass;
     var listType = listClass.thisType;
     List<DartType> inferredTypes;
@@ -1659,7 +1632,7 @@
       }
     }
     var inferredType = new InterfaceType(listClass, [inferredTypeArgument]);
-    inferrer.listener.listLiteralExit(fileOffset, inferredType);
+    inferrer.listener.listLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1677,17 +1650,15 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.logicalExpressionEnter(fileOffset, typeContext);
     var boolType = inferrer.coreTypes.boolClass.rawType;
     var leftType =
         inferrer.inferExpression(factory, left, boolType, !inferrer.isTopLevel);
-    inferrer.listener.logicalExpressionBeforeRhs(fileOffset);
     var rightType = inferrer.inferExpression(
         factory, right, boolType, !inferrer.isTopLevel);
     inferrer.ensureAssignable(boolType, leftType, left, left.fileOffset);
     inferrer.ensureAssignable(boolType, rightType, right, right.fileOffset);
     var inferredType = boolType;
-    inferrer.listener.logicalExpressionExit(fileOffset, inferredType);
+    inferrer.listener.logicalExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1728,7 +1699,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.mapLiteralEnter(fileOffset, typeContext);
     var mapClass = inferrer.coreTypes.mapClass;
     var mapType = mapClass.thisType;
     List<DartType> inferredTypes;
@@ -1799,7 +1769,7 @@
     }
     var inferredType =
         new InterfaceType(mapClass, [inferredKeyType, inferredValueType]);
-    inferrer.listener.mapLiteralExit(fileOffset, inferredType);
+    inferrer.listener.mapLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1870,11 +1840,10 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.namedFunctionExpressionEnter(fileOffset, typeContext);
     var inferredType = inferrer.inferExpression(
         factory, variable.initializer, typeContext, true);
     if (inferrer.strongMode) variable.type = inferredType;
-    inferrer.listener.namedFunctionExpressionExit(fileOffset, inferredType);
+    inferrer.listener.namedFunctionExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1890,14 +1859,13 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.notEnter(fileOffset, typeContext);
     // First infer the receiver so we can look up the method that was invoked.
     var boolType = inferrer.coreTypes.boolClass.rawType;
     var actualType = inferrer.inferExpression(
         factory, operand, boolType, !inferrer.isTopLevel);
     inferrer.ensureAssignable(boolType, actualType, operand, fileOffset);
     DartType inferredType = boolType;
-    inferrer.listener.notExit(fileOffset, inferredType);
+    inferrer.listener.not(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1979,10 +1947,9 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.nullLiteralEnter(fileOffset, typeContext);
     inferredType = inferrer.coreTypes.nullClass.rawType;
     inferrer.listener
-        .nullLiteralExit(fileOffset, fileOffset == -1, inferredType);
+        .nullLiteral(this, fileOffset, fileOffset == -1, inferredType);
     return inferredType;
   }
 }
@@ -2055,7 +2022,6 @@
       DartType typeContext) {
     var receiverType = _inferReceiver(inferrer, factory);
 
-    inferrer.listener.propertyAssignEnter(write.fileOffset, typeContext);
     DartType readType;
     if (read != null) {
       var readMember =
@@ -2075,7 +2041,8 @@
     var writeContext = inferrer.getSetterType(writeMember, receiverType);
     var inferredResult = _inferRhs(inferrer, factory, readType, writeContext);
     if (inferrer.strongMode) nullAwareGuard?.staticType = inferredResult.type;
-    inferrer.listener.propertyAssignExit(
+    inferrer.listener.propertyAssign(
+        this,
         write.fileOffset,
         inferrer.getRealTarget(writeMember),
         writeContext,
@@ -2121,7 +2088,6 @@
   @override
   infer<Expression, Statement, Initializer, Type>(ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.redirectingInitializerEnter(fileOffset, target);
     List<TypeParameter> classTypeParameters =
         target.enclosingClass.typeParameters;
     List<DartType> typeArguments =
@@ -2134,7 +2100,7 @@
         target.function.functionType, target.enclosingClass.thisType, arguments,
         skipTypeArgumentInference: true);
     ArgumentsJudgment.removeNonInferrableArgumentTypes(arguments);
-    inferrer.listener.redirectingInitializerExit(fileOffset);
+    inferrer.listener.redirectingInitializer(this, fileOffset, target);
   }
 }
 
@@ -2147,9 +2113,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.rethrowEnter(fileOffset, typeContext);
     var inferredType = const BottomType();
-    inferrer.listener.rethrowExit(fileOffset, inferredType);
+    inferrer.listener.rethrow_(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2164,7 +2129,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.returnStatementEnter(fileOffset);
     var judgment = this.judgment;
     var closureContext = inferrer.closureContext;
     var typeContext = !closureContext.isGenerator
@@ -2184,7 +2148,7 @@
       closureContext.handleReturn(
           inferrer, inferredType, expression, fileOffset);
     }
-    inferrer.listener.returnStatementExit(fileOffset);
+    inferrer.listener.returnStatement(this, fileOffset);
   }
 }
 
@@ -2213,7 +2177,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.staticAssignEnter(this.write?.fileOffset, typeContext);
     DartType readType = const DynamicType(); // Only used in error recovery
     var read = this.read;
     if (read is StaticGet) {
@@ -2232,7 +2195,7 @@
       }
     }
     var inferredResult = _inferRhs(inferrer, factory, readType, writeContext);
-    inferrer.listener.staticAssignExit(write?.fileOffset, writeMember,
+    inferrer.listener.staticAssign(this, write?.fileOffset, writeMember,
         writeContext, inferredResult.combiner, inferredResult.type);
     _replaceWithDesugared();
     return inferredResult.type;
@@ -2251,7 +2214,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.staticGetEnter(fileOffset, typeContext);
     var target = this.target;
     if (target is ShadowField && target.inferenceNode != null) {
       target.inferenceNode.resolve();
@@ -2262,7 +2224,7 @@
       type = inferrer.instantiateTearOff(type, typeContext, this);
     }
     inferredType = type;
-    inferrer.listener.staticGetExit(fileOffset, target, inferredType);
+    inferrer.listener.staticGet(this, fileOffset, target, inferredType);
     return inferredType;
   }
 }
@@ -2281,13 +2243,12 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.staticInvocationEnter(
-        this.fileOffset, arguments.fileOffset, typeContext);
     var calleeType = target.function.functionType;
     var inferredType = inferrer.inferInvocation(factory, typeContext,
         fileOffset, calleeType, calleeType.returnType, arguments);
-    inferrer.listener.staticInvocationExit(
-        fileOffset,
+    inferrer.listener.staticInvocation(
+        this,
+        arguments.fileOffset,
         target,
         arguments.types,
         inferrer.lastCalleeType,
@@ -2309,7 +2270,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.stringConcatenationEnter(fileOffset, typeContext);
     if (!inferrer.isTopLevel) {
       for (kernel.Expression expression in expressions) {
         inferrer.inferExpression(
@@ -2317,7 +2277,7 @@
       }
     }
     var inferredType = inferrer.coreTypes.stringClass.rawType;
-    inferrer.listener.stringConcatenationExit(fileOffset, inferredType);
+    inferrer.listener.stringConcatenation(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2333,9 +2293,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.stringLiteralEnter(fileOffset, typeContext);
     var inferredType = inferrer.coreTypes.stringClass.rawType;
-    inferrer.listener.stringLiteralExit(fileOffset, inferredType);
+    inferrer.listener.stringLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2350,7 +2309,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.superInitializerEnter(fileOffset);
     var substitution = Substitution.fromSupertype(inferrer.classHierarchy
         .getClassAsInstanceOf(
             inferrer.thisType.classNode, target.enclosingClass));
@@ -2363,7 +2321,7 @@
         inferrer.thisType,
         arguments,
         skipTypeArgumentInference: true);
-    inferrer.listener.superInitializerExit(fileOffset);
+    inferrer.listener.superInitializer(this, fileOffset);
   }
 }
 
@@ -2446,7 +2404,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.switchStatementEnter(fileOffset);
     var expressionJudgment = this.expressionJudgment;
     inferrer.inferExpression(
         factory, expressionJudgment, const UnknownType(), true);
@@ -2458,7 +2415,7 @@
       }
       inferrer.inferStatement(factory, switchCase.bodyJudgment);
     }
-    inferrer.listener.switchStatementExit(fileOffset);
+    inferrer.listener.switchStatement(this, fileOffset);
   }
 }
 
@@ -2473,9 +2430,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.symbolLiteralEnter(fileOffset, typeContext);
     var inferredType = inferrer.coreTypes.symbolClass.rawType;
-    inferrer.listener.symbolLiteralExit(fileOffset, inferredType);
+    inferrer.listener.symbolLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2556,9 +2512,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.thisExpressionEnter(fileOffset, typeContext);
     inferredType = inferrer.thisType ?? const DynamicType();
-    inferrer.listener.thisExpressionExit(fileOffset, inferredType);
+    inferrer.listener.thisExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2575,10 +2530,9 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.throwEnter(fileOffset, typeContext);
     inferrer.inferExpression(factory, judgment, const UnknownType(), false);
     inferredType = const BottomType();
-    inferrer.listener.throwExit(fileOffset, inferredType);
+    inferrer.listener.throw_(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2608,20 +2562,19 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.tryCatchEnter(fileOffset);
     inferrer.inferStatement(factory, bodyJudgment);
     for (var catch_ in catchJudgments) {
-      inferrer.listener.catchStatementEnter(
+      inferrer.inferStatement(factory, catch_.bodyJudgment);
+      inferrer.listener.catchStatement(
+          catch_,
           catch_.fileOffset,
           catch_.guard,
           catch_.exceptionJudgment?.fileOffset,
           catch_.exceptionJudgment?.type,
           catch_.stackTraceJudgment?.fileOffset,
           catch_.stackTraceJudgment?.type);
-      inferrer.inferStatement(factory, catch_.bodyJudgment);
-      inferrer.listener.catchStatementExit(catch_.fileOffset);
     }
-    inferrer.listener.tryCatchExit(fileOffset);
+    inferrer.listener.tryCatch(this, fileOffset);
   }
 }
 
@@ -2634,10 +2587,9 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.tryFinallyEnter(fileOffset);
     inferrer.inferStatement(factory, body);
     inferrer.inferStatement(factory, finalizer);
-    inferrer.listener.tryFinallyExit(fileOffset);
+    inferrer.listener.tryFinally(this, fileOffset);
   }
 }
 
@@ -2799,9 +2751,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.typeLiteralEnter(fileOffset, typeContext);
     inferredType = inferrer.coreTypes.typeClass.rawType;
-    inferrer.listener.typeLiteralExit(fileOffset, type, inferredType);
+    inferrer.listener.typeLiteral(this, fileOffset, type, inferredType);
     return inferredType;
   }
 }
@@ -2889,7 +2840,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.variableAssignEnter(this.write.fileOffset, typeContext);
     DartType readType;
     var read = this.read;
     if (read is VariableGet) {
@@ -2904,7 +2854,8 @@
       }
     }
     var inferredResult = _inferRhs(inferrer, factory, readType, writeContext);
-    inferrer.listener.variableAssignExit(
+    inferrer.listener.variableAssign(
+        this,
         write.fileOffset,
         writeContext,
         write is VariableSet ? write.variable.fileOffset : null,
@@ -2966,7 +2917,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.variableDeclarationEnter(fileOffset);
     if (annotationJudgments.isNotEmpty) {
       inferrer.inferMetadataKeepingHelper(factory, annotationJudgments);
 
@@ -3013,8 +2963,8 @@
         initializer = replacedInitializer;
       }
     }
-    inferrer.listener.variableDeclarationExit(
-        fileOffset, type, _implicitlyTyped ? inferredType : type);
+    inferrer.listener.variableDeclaration(
+        this, fileOffset, type, _implicitlyTyped ? inferredType : type);
   }
 
   /// Determine whether the given [VariableDeclarationJudgment] had an implicit
@@ -3067,7 +3017,6 @@
     bool mutatedInClosure = variable._mutatedInClosure;
     DartType declaredOrInferredType = variable.type;
 
-    inferrer.listener.variableGetEnter(fileOffset, typeContext);
     DartType promotedType = inferrer.typePromoter
         .computePromotedType(_fact, _scope, mutatedInClosure);
     if (promotedType != null) {
@@ -3080,8 +3029,8 @@
       type = inferrer.instantiateTearOff(type, typeContext, this);
     }
     inferredType = type;
-    inferrer.listener.variableGetExit(
-        fileOffset, _isInCascade(), variable.fileOffset, inferredType);
+    inferrer.listener.variableGet(
+        this, fileOffset, _isInCascade(), variable.fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -3098,7 +3047,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.whileStatementEnter(fileOffset);
     var conditionJudgment = this.conditionJudgment;
     var expectedType = inferrer.coreTypes.boolClass.rawType;
     inferrer.inferExpression(
@@ -3106,7 +3054,7 @@
     inferrer.ensureAssignable(expectedType, conditionJudgment.inferredType,
         condition, condition.fileOffset);
     inferrer.inferStatement(factory, bodyJudgment);
-    inferrer.listener.whileStatementExit(fileOffset);
+    inferrer.listener.whileStatement(this, fileOffset);
   }
 }
 
@@ -3121,7 +3069,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.yieldStatementEnter(fileOffset);
     var judgment = this.judgment;
     var closureContext = inferrer.closureContext;
     if (closureContext.isGenerator) {
@@ -3139,7 +3086,7 @@
     }
     closureContext.handleYield(
         inferrer, isYieldStar, judgment.inferredType, expression, fileOffset);
-    inferrer.listener.yieldStatementExit(fileOffset);
+    inferrer.listener.yieldStatement(this, fileOffset);
   }
 }
 
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 543eff4..961ebe3 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -42,7 +42,7 @@
 import '../type_inference/type_inference_engine.dart' show TypeInferenceEngine;
 
 import '../type_inference/type_inference_listener.dart'
-    show TypeInferenceListener;
+    show KernelTypeInferenceListener, TypeInferenceListener;
 
 import 'source_library_builder.dart' show SourceLibraryBuilder;
 
@@ -534,7 +534,7 @@
       ModifierBuilder builder, Scope memberScope, bool isInstanceMember,
       [Scope formalParameterScope,
       TypeInferenceListener<int, int, Node, int> listener]) {
-    listener ??= new TypeInferenceListener<int, int, Node, int>();
+    listener ??= new KernelTypeInferenceListener();
     // Note: we set thisType regardless of whether we are building a static
     // member, since that provides better error recovery.
     InterfaceType thisType = currentClass?.target?.thisType;
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart
index 28ea849..fcf385f 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart
@@ -2,29 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE.md file.
 
-import 'package:kernel/ast.dart' show DartType, FunctionType;
+import 'package:kernel/ast.dart' show Catch, DartType, FunctionType, Node;
 
 import 'package:kernel/type_algebra.dart' show Substitution;
 
-/// Base class for [TypeInferenceListener] that defines the API for debugging.
-///
-/// By default no debug info is printed.  To enable debug printing, mix in
-/// [TypeInferenceDebugging].
-class TypeInferenceBase<Location> {
-  void genericExpressionEnter(
-      String expressionType, Location location, DartType typeContext) {}
-
-  void genericExpressionExit(
-      String expressionType, Location location, DartType inferredType) {}
-
-  void genericInitializerEnter(String initializerType, Location location) {}
-
-  void genericInitializerExit(String initializerType, Location location) {}
-
-  void genericStatementEnter(String statementType, Location location) {}
-
-  void genericStatementExit(String statementType, Location location) {}
-}
+import '../kernel/kernel_shadow_ast.dart'
+    show ExpressionJudgment, InitializerJudgment, StatementJudgment;
 
 /// Callback interface used by [TypeInferrer] to report the results of type
 /// inference to a client.
@@ -38,444 +21,502 @@
 /// The default implementation (in this base class) does nothing, however it can
 /// be used to debug type inference by uncommenting the
 /// "with TypeInferenceDebugging" clause below.
-class TypeInferenceListener<Location, Declaration, Reference, PrefixInfo>
-    extends TypeInferenceBase<Location> {
-  void asExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("asExpression", location, typeContext);
+abstract class TypeInferenceListener<Location, Declaration, Reference,
+    PrefixInfo> {
+  void asExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void asExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("asExpression", location, inferredType);
+  void assertInitializer(InitializerJudgment judgment, Location location);
 
-  void assertInitializerEnter(Location location) =>
-      genericInitializerEnter("assertInitializer", location);
+  void assertStatement(StatementJudgment judgment, Location location);
 
-  void assertInitializerExit(Location location) =>
-      genericInitializerExit("assertInitializer", location);
+  void awaitExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void assertStatementEnter(Location location) =>
-      genericStatementEnter('assertStatement', location);
+  void block(StatementJudgment judgment, Location location);
 
-  void assertStatementExit(Location location) =>
-      genericStatementExit('assertStatement', location);
+  void boolLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void awaitExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("awaitExpression", location, typeContext);
+  void breakStatement(StatementJudgment judgment, Location location);
 
-  void awaitExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("awaitExpression", location, inferredType);
+  void cascadeExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void blockEnter(Location location) =>
-      genericStatementEnter('block', location);
-
-  void blockExit(Location location) => genericStatementExit('block', location);
-
-  void boolLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("boolLiteral", location, typeContext);
-
-  void boolLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("boolLiteral", location, inferredType);
-
-  void breakStatementEnter(Location location) =>
-      genericStatementEnter('breakStatement', location);
-
-  void breakStatementExit(Location location) =>
-      genericStatementExit('breakStatement', location);
-
-  void cascadeExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("cascade", location, typeContext);
-
-  void cascadeExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("cascade", location, inferredType);
-
-  void catchStatementEnter(
+  void catchStatement(
+      Catch judgment,
       Location location,
       DartType guardType,
       Location exceptionLocation,
       DartType exceptionType,
       Location stackTraceLocation,
-      DartType stackTraceType) {}
+      DartType stackTraceType);
 
-  void catchStatementExit(Location location) {}
+  void conditionalExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void conditionalExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("conditionalExpression", location, typeContext);
+  void constructorInvocation(ExpressionJudgment judgment, Location location,
+      Reference expressionTarget, DartType inferredType);
 
-  void conditionalExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("conditionalExpression", location, inferredType);
+  void continueSwitchStatement(StatementJudgment judgment, Location location);
 
-  void constructorInvocationEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("constructorInvocation", location, typeContext);
+  void deferredCheck(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void constructorInvocationExit(Location location, Reference expressionTarget,
-          DartType inferredType) =>
-      genericExpressionExit("constructorInvocation", location, inferredType);
+  void doStatement(StatementJudgment judgment, Location location);
 
-  void continueSwitchStatementEnter(Location location) =>
-      genericStatementEnter('continueSwitchStatement', location);
+  void doubleLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void continueSwitchStatementExit(Location location) =>
-      genericStatementExit('continueSwitchStatement', location);
+  void expressionStatement(StatementJudgment judgment, Location location);
 
-  void deferredCheckEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("deferredCheck", location, typeContext);
+  void fieldInitializer(InitializerJudgment judgment, Location location,
+      Reference initializerField);
 
-  void deferredCheckExit(Location location, DartType inferredType) =>
-      genericExpressionExit("deferredCheck", location, inferredType);
+  void forInStatement(
+      StatementJudgment judgment,
+      Location location,
+      Location variableLocation,
+      DartType variableType,
+      Location writeLocation,
+      DartType writeVariableType,
+      Declaration writeVariable,
+      Reference writeTarget);
 
-  void doStatementEnter(Location location) =>
-      genericStatementEnter("doStatement", location);
+  void forStatement(StatementJudgment judgment, Location location);
 
-  void doStatementExit(Location location) =>
-      genericStatementExit("doStatement", location);
+  void functionDeclaration(
+      StatementJudgment judgment, Location location, FunctionType inferredType);
 
-  void doubleLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("doubleLiteral", location, typeContext);
+  void functionExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void doubleLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("doubleLiteral", location, inferredType);
+  void ifNull(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void dryRunEnter(Location location) =>
-      genericExpressionEnter("dryRun", location, null);
+  void ifStatement(StatementJudgment judgment, Location location);
 
-  void dryRunExit(Location location) =>
-      genericExpressionExit("dryRun", location, null);
+  void indexAssign(ExpressionJudgment judgment, Location location,
+      Reference writeMember, Reference combiner, DartType inferredType);
 
-  void expressionStatementEnter(Location location) =>
-      genericStatementEnter('expressionStatement', location);
+  void intLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void expressionStatementExit(Location location) =>
-      genericStatementExit('expressionStatement', location);
+  void invalidInitializer(InitializerJudgment judgment, Location location);
 
-  void fieldInitializerEnter(Location location, Reference initializerField) =>
-      genericInitializerEnter("fieldInitializer", location);
+  void isExpression(ExpressionJudgment judgment, Location location,
+      DartType testedType, DartType inferredType);
 
-  void fieldInitializerExit(Location location) =>
-      genericInitializerExit("fieldInitializer", location);
+  void isNotExpression(ExpressionJudgment judgment, Location location,
+      DartType type, DartType inferredType);
 
-  void forInStatementEnter(
-          Location location,
-          Location variableLocation,
-          Location writeLocation,
-          DartType writeVariableType,
-          Declaration writeVariable,
-          Reference writeTarget) =>
-      genericStatementEnter('forInStatement', location);
+  void labeledStatement(StatementJudgment judgment, Location location);
 
-  void forInStatementExit(
-          Location location, bool variablePresent, DartType variableType) =>
-      genericStatementExit('forInStatement', location);
+  void listLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void forStatementEnter(Location location) =>
-      genericStatementEnter('forStatement', location);
+  void logicalExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void forStatementExit(Location location) =>
-      genericStatementExit('forStatement', location);
+  void mapLiteral(
+      ExpressionJudgment judgment, Location location, DartType typeContext);
 
-  void functionDeclarationEnter(Location location) =>
-      genericStatementEnter('functionDeclaration', location);
+  void methodInvocation(
+      ExpressionJudgment judgment,
+      Location resultOffset,
+      List<DartType> argumentsTypes,
+      bool isImplicitCall,
+      Reference interfaceMember,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType);
 
-  void functionDeclarationExit(Location location, FunctionType inferredType) =>
-      genericStatementExit('functionDeclaration', location);
+  void methodInvocationCall(
+      ExpressionJudgment judgment,
+      Location resultOffset,
+      List<DartType> argumentsTypes,
+      bool isImplicitCall,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType);
 
-  void functionExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("functionExpression", location, typeContext);
+  void namedFunctionExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void functionExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("functionExpression", location, inferredType);
+  void not(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void ifNullBeforeRhs(Location location) {}
+  void nullLiteral(ExpressionJudgment judgment, Location location,
+      bool isSynthetic, DartType inferredType);
 
-  void ifNullEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter('ifNull', location, typeContext);
+  void propertyAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      Reference writeMember,
+      DartType writeContext,
+      Reference combiner,
+      DartType inferredType);
 
-  void ifNullExit(Location location, DartType inferredType) =>
-      genericExpressionExit('ifNull', location, inferredType);
+  void propertyGet(ExpressionJudgment judgment, Location location,
+      Reference member, DartType inferredType);
 
-  void ifStatementEnter(Location location) =>
-      genericStatementEnter('ifStatement', location);
+  void propertyGetCall(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void ifStatementExit(Location location) =>
-      genericStatementExit('ifStatement', location);
+  void propertySet(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void indexAssignAfterReceiver(Location location, DartType typeContext) {}
+  void redirectingInitializer(InitializerJudgment judgment, Location location,
+      Reference initializerTarget);
 
-  void indexAssignEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("indexAssign", location, typeContext);
+  void rethrow_(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void indexAssignExit(Location location, Reference writeMember,
-          Reference combiner, DartType inferredType) =>
-      genericExpressionExit("indexAssign", location, inferredType);
+  void returnStatement(StatementJudgment judgment, Location location);
 
-  void intLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("intLiteral", location, typeContext);
+  void staticAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      Reference writeMember,
+      DartType writeContext,
+      Reference combiner,
+      DartType inferredType);
 
-  void intLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("intLiteral", location, inferredType);
+  void staticGet(ExpressionJudgment judgment, Location location,
+      Reference expressionTarget, DartType inferredType);
 
-  void invalidInitializerEnter(Location location) =>
-      genericInitializerEnter("invalidInitializer", location);
+  void staticInvocation(
+      ExpressionJudgment judgment,
+      Location location,
+      Reference expressionTarget,
+      List<DartType> expressionArgumentsTypes,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType);
 
-  void invalidInitializerExit(Location location) =>
-      genericInitializerExit("invalidInitializer", location);
+  void stringConcatenation(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void isExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("isExpression", location, typeContext);
+  void stringLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void isExpressionExit(
-          Location location, DartType testedType, DartType inferredType) =>
-      genericExpressionExit("isExpression", location, inferredType);
+  void superInitializer(InitializerJudgment judgment, Location location);
 
-  void isNotExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("isNotExpression", location, typeContext);
+  void switchStatement(StatementJudgment judgment, Location location);
 
-  void isNotExpressionExit(
-          Location location, DartType type, DartType inferredType) =>
-      genericExpressionExit("isNotExpression", location, inferredType);
+  void symbolLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void labeledStatementEnter(Location location) =>
-      genericStatementEnter('labeledStatement', location);
+  void thisExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void labeledStatementExit(Location location) =>
-      genericStatementExit('labeledStatement', location);
+  void throw_(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void listLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("listLiteral", location, typeContext);
+  void tryCatch(StatementJudgment judgment, Location location);
 
-  void listLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("listLiteral", location, inferredType);
+  void tryFinally(StatementJudgment judgment, Location location);
 
-  void logicalExpressionBeforeRhs(Location location) {}
+  void typeLiteral(ExpressionJudgment judgment, Location location,
+      Reference expressionType, DartType inferredType);
 
-  void logicalExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("logicalExpression", location, typeContext);
-
-  void logicalExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("logicalExpression", location, inferredType);
-
-  void mapLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("mapLiteral", location, typeContext);
-
-  void mapLiteralExit(Location location, DartType typeContext) =>
-      genericExpressionExit("mapLiteral", location, typeContext);
-
-  void methodInvocationBeforeArgs(Location location, bool isImplicitCall) {}
-
-  void methodInvocationEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("methodInvocation", location, typeContext);
-
-  void methodInvocationExit(
-          Location resultOffset,
-          List<DartType> argumentsTypes,
-          bool isImplicitCall,
-          Reference interfaceMember,
-          FunctionType calleeType,
-          Substitution substitution,
-          DartType inferredType) =>
-      genericExpressionExit("methodInvocation", resultOffset, inferredType);
-
-  void methodInvocationExitCall(
-          Location resultOffset,
-          List<DartType> argumentsTypes,
-          bool isImplicitCall,
-          FunctionType calleeType,
-          Substitution substitution,
-          DartType inferredType) =>
-      genericExpressionExit("methodInvocation", resultOffset, inferredType);
-
-  void namedFunctionExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("namedFunctionExpression", location, typeContext);
-
-  void namedFunctionExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("namedFunctionExpression", location, inferredType);
-
-  void notEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("not", location, typeContext);
-
-  void notExit(Location location, DartType inferredType) =>
-      genericExpressionExit("not", location, inferredType);
-
-  void nullLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("nullLiteral", location, typeContext);
-
-  void nullLiteralExit(
-          Location location, bool isSynthetic, DartType inferredType) =>
-      genericExpressionExit("nullLiteral", location, inferredType);
-
-  void propertyAssignEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("propertyAssign", location, typeContext);
-
-  void propertyAssignExit(Location location, Reference writeMember,
-          DartType writeContext, Reference combiner, DartType inferredType) =>
-      genericExpressionExit("propertyAssign", location, inferredType);
-
-  void propertyGetEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("propertyGet", location, typeContext);
-
-  void propertyGetExit(
-          Location location, Reference member, DartType inferredType) =>
-      genericExpressionExit("propertyGet", location, inferredType);
-
-  void propertyGetExitCall(Location location, DartType inferredType) =>
-      genericExpressionExit("propertyGet", location, inferredType);
-
-  void propertySetEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("propertySet", location, typeContext);
-
-  void propertySetExit(Location location, DartType inferredType) =>
-      genericExpressionExit("propertySet", location, inferredType);
-
-  void redirectingInitializerEnter(
-          Location location, Reference initializerTarget) =>
-      genericInitializerEnter("redirectingInitializer", location);
-
-  void redirectingInitializerExit(Location location) =>
-      genericInitializerExit("redirectingInitializer", location);
-
-  void rethrowEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter('rethrow', location, typeContext);
-
-  void rethrowExit(Location location, DartType inferredType) =>
-      genericExpressionExit('rethrow', location, inferredType);
-
-  void returnStatementEnter(Location location) =>
-      genericStatementEnter('returnStatement', location);
-
-  void returnStatementExit(Location location) =>
-      genericStatementExit('returnStatement', location);
-
-  void staticAssignEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("staticAssign", location, typeContext);
-
-  void staticAssignExit(Location location, Reference writeMember,
-          DartType writeContext, Reference combiner, DartType inferredType) =>
-      genericExpressionExit("staticAssign", location, inferredType);
-
-  void staticGetEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("staticGet", location, typeContext);
-
-  void staticGetExit(Location location, Reference expressionTarget,
-          DartType inferredType) =>
-      genericExpressionExit("staticGet", location, inferredType);
-
-  void staticInvocationEnter(Location location,
-          Location expressionArgumentsLocation, DartType typeContext) =>
-      genericExpressionEnter("staticInvocation", location, typeContext);
-
-  void staticInvocationExit(
-          Location location,
-          Reference expressionTarget,
-          List<DartType> expressionArgumentsTypes,
-          FunctionType calleeType,
-          Substitution substitution,
-          DartType inferredType) =>
-      genericExpressionExit("staticInvocation", location, inferredType);
-
-  void stringConcatenationEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("stringConcatenation", location, typeContext);
-
-  void stringConcatenationExit(Location location, DartType inferredType) =>
-      genericExpressionExit("stringConcatenation", location, inferredType);
-
-  void stringLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("StringLiteral", location, typeContext);
-
-  void stringLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("StringLiteral", location, inferredType);
-
-  void superInitializerEnter(Location location) =>
-      genericInitializerEnter("superInitializer", location);
-
-  void superInitializerExit(Location location) =>
-      genericInitializerExit("superInitializer", location);
-
-  void switchStatementEnter(Location location) =>
-      genericStatementEnter('switchStatement', location);
-
-  void switchStatementExit(Location location) =>
-      genericStatementExit('switchStatement', location);
-
-  void symbolLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("symbolLiteral", location, typeContext);
-
-  void symbolLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("symbolLiteral", location, inferredType);
-
-  void thisExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("thisExpression", location, typeContext);
-
-  void thisExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("thisExpression", location, inferredType);
-
-  void throwEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter('throw', location, typeContext);
-
-  void throwExit(Location location, DartType inferredType) =>
-      genericExpressionExit('throw', location, inferredType);
-
-  void tryCatchEnter(Location location) =>
-      genericStatementEnter('tryCatch', location);
-
-  void tryCatchExit(Location location) =>
-      genericStatementExit('tryCatch', location);
-
-  void tryFinallyEnter(Location location) =>
-      genericStatementEnter('tryFinally', location);
-
-  void tryFinallyExit(Location location) =>
-      genericStatementExit('tryFinally', location);
-
-  void typeLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("typeLiteral", location, typeContext);
-
-  void typeLiteralExit(
-          Location location, Reference expressionType, DartType inferredType) =>
-      genericExpressionExit("typeLiteral", location, inferredType);
-
-  void variableAssignEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("variableAssign", location, typeContext);
-
-  void variableAssignExit(
-          Location location,
-          DartType writeContext,
-          Declaration writeVariable,
-          Reference combiner,
-          DartType inferredType) =>
-      genericExpressionExit("variableAssign", location, inferredType);
-
-  void variableDeclarationEnter(Location location) =>
-      genericStatementEnter('variableDeclaration', location);
-
-  void variableDeclarationExit(
-          Location location, DartType statementType, DartType inferredType) =>
-      genericStatementExit('variableDeclaration', location);
-
-  void variableGetEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("variableGet", location, typeContext);
-
-  void variableGetExit(Location location, bool isInCascade,
-          Declaration expressionVariable, DartType inferredType) =>
-      genericExpressionExit("variableGet", location, inferredType);
-
-  void variableSetEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("variableSet", location, typeContext);
+  void variableAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      DartType writeContext,
+      Declaration writeVariable,
+      Reference combiner,
+      DartType inferredType);
 
-  void variableSetExit(Location location, DartType inferredType) =>
-      genericExpressionExit("variableSet", location, inferredType);
+  void variableDeclaration(StatementJudgment judgment, Location location,
+      DartType statementType, DartType inferredType);
 
-  void whileStatementEnter(Location location) =>
-      genericStatementEnter("whileStatement", location);
+  void variableGet(ExpressionJudgment judgment, Location location,
+      bool isInCascade, Declaration expressionVariable, DartType inferredType);
 
-  void whileStatementExit(Location location) =>
-      genericStatementExit("whileStatement", location);
+  void variableSet(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void yieldStatementEnter(Location location) =>
-      genericStatementEnter('yieldStatement', location);
+  void whileStatement(StatementJudgment judgment, Location location);
 
-  void yieldStatementExit(Location location) =>
-      genericStatementExit('yieldStatement', location);
+  void yieldStatement(StatementJudgment judgment, Location location);
 
-  void storePrefixInfo(Location location, PrefixInfo prefixInfo) {}
+  void storePrefixInfo(Location location, PrefixInfo prefixInfo);
 
   void storeClassReference(
-      Location location, Reference reference, DartType rawType) {}
+      Location location, Reference reference, DartType rawType);
+}
+
+/// Kernel implementation of TypeInferenceListener; does nothing.
+///
+/// TODO(paulberry): fuse this with KernelFactory.
+class KernelTypeInferenceListener
+    implements TypeInferenceListener<int, int, Node, int> {
+  @override
+  void asExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void assertInitializer(InitializerJudgment judgment, location) {}
+
+  @override
+  void assertStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void awaitExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void block(StatementJudgment judgment, location) {}
+
+  @override
+  void boolLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void breakStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void cascadeExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void catchStatement(
+      Catch judgment,
+      location,
+      DartType guardType,
+      exceptionLocation,
+      DartType exceptionType,
+      stackTraceLocation,
+      DartType stackTraceType) {}
+
+  @override
+  void conditionalExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void constructorInvocation(ExpressionJudgment judgment, location,
+      expressionTarget, DartType inferredType) {}
+
+  @override
+  void continueSwitchStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void deferredCheck(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void doStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void doubleLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void expressionStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void fieldInitializer(
+      InitializerJudgment judgment, location, initializerField) {}
+
+  @override
+  void forInStatement(
+      StatementJudgment judgment,
+      location,
+      variableLocation,
+      DartType variableType,
+      writeLocation,
+      DartType writeVariableType,
+      writeVariable,
+      writeTarget) {}
+
+  @override
+  void forStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void functionDeclaration(
+      StatementJudgment judgment, location, FunctionType inferredType) {}
+
+  @override
+  void functionExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void ifNull(ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void ifStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void indexAssign(ExpressionJudgment judgment, location, writeMember, combiner,
+      DartType inferredType) {}
+
+  @override
+  void intLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void invalidInitializer(InitializerJudgment judgment, location) {}
+
+  @override
+  void isExpression(ExpressionJudgment judgment, location, DartType testedType,
+      DartType inferredType) {}
+
+  @override
+  void isNotExpression(ExpressionJudgment judgment, location, DartType type,
+      DartType inferredType) {}
+
+  @override
+  void labeledStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void listLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void logicalExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void mapLiteral(
+      ExpressionJudgment judgment, location, DartType typeContext) {}
+
+  @override
+  void methodInvocation(
+      ExpressionJudgment judgment,
+      resultOffset,
+      List<DartType> argumentsTypes,
+      bool isImplicitCall,
+      interfaceMember,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType) {}
+
+  @override
+  void methodInvocationCall(
+      ExpressionJudgment judgment,
+      resultOffset,
+      List<DartType> argumentsTypes,
+      bool isImplicitCall,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType) {}
+
+  @override
+  void namedFunctionExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void not(ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void nullLiteral(ExpressionJudgment judgment, location, bool isSynthetic,
+      DartType inferredType) {}
+
+  @override
+  void propertyAssign(ExpressionJudgment judgment, location, writeMember,
+      DartType writeContext, combiner, DartType inferredType) {}
+
+  @override
+  void propertyGet(
+      ExpressionJudgment judgment, location, member, DartType inferredType) {}
+
+  @override
+  void propertyGetCall(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void propertySet(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void redirectingInitializer(
+      InitializerJudgment judgment, location, initializerTarget) {}
+
+  @override
+  void rethrow_(ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void returnStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void staticAssign(ExpressionJudgment judgment, location, writeMember,
+      DartType writeContext, combiner, DartType inferredType) {}
+
+  @override
+  void staticGet(ExpressionJudgment judgment, location, expressionTarget,
+      DartType inferredType) {}
+
+  @override
+  void staticInvocation(
+      ExpressionJudgment judgment,
+      location,
+      expressionTarget,
+      List<DartType> expressionArgumentsTypes,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType) {}
+
+  @override
+  void storeClassReference(location, reference, DartType rawType) {}
+
+  @override
+  void storePrefixInfo(location, prefixInfo) {}
+
+  @override
+  void stringConcatenation(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void stringLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void superInitializer(InitializerJudgment judgment, location) {}
+
+  @override
+  void switchStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void symbolLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void thisExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void throw_(ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void tryCatch(StatementJudgment judgment, location) {}
+
+  @override
+  void tryFinally(StatementJudgment judgment, location) {}
+
+  @override
+  void typeLiteral(ExpressionJudgment judgment, location, expressionType,
+      DartType inferredType) {}
+
+  @override
+  void variableAssign(ExpressionJudgment judgment, location,
+      DartType writeContext, writeVariable, combiner, DartType inferredType) {}
+
+  @override
+  void variableDeclaration(StatementJudgment judgment, location,
+      DartType statementType, DartType inferredType) {}
+
+  @override
+  void variableGet(ExpressionJudgment judgment, location, bool isInCascade,
+      expressionVariable, DartType inferredType) {}
+
+  @override
+  void variableSet(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void whileStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void yieldStatement(StatementJudgment judgment, location) {}
 }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 95e550b..521c12f 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -1425,12 +1425,10 @@
       Object interfaceMember,
       Name methodName,
       Arguments arguments}) {
-    listener.methodInvocationEnter(expression.fileOffset, typeContext);
     // First infer the receiver so we can look up the method that was invoked.
     var receiverType = receiver == null
         ? thisType
         : inferExpression(factory, receiver, const UnknownType(), true);
-    listener.methodInvocationBeforeArgs(expression.fileOffset, isImplicitCall);
     if (strongMode) {
       receiverVariable?.type = receiverType;
     }
@@ -1462,7 +1460,8 @@
         ? arguments.fileOffset
         : expression.fileOffset;
     if (identical(interfaceMember, 'call')) {
-      listener.methodInvocationExitCall(
+      listener.methodInvocationCall(
+          expression,
           resultOffset,
           arguments.types,
           isImplicitCall,
@@ -1482,7 +1481,8 @@
             templateImplicitCallOfNonMethod.withArguments(receiverType));
         parent?.replaceChild(expression, errorNode);
       }
-      listener.methodInvocationExit(
+      listener.methodInvocation(
+          expression,
           resultOffset,
           arguments.types,
           isImplicitCall,
@@ -1521,7 +1521,6 @@
       PropertyGet desugaredGet,
       Object interfaceMember,
       Name propertyName}) {
-    listener.propertyGetEnter(expression.fileOffset, typeContext);
     // First infer the receiver so we can look up the getter that was invoked.
     DartType receiverType;
     if (receiver == null) {
@@ -1557,10 +1556,10 @@
           instantiateTearOff(inferredType, typeContext, replacedExpression);
     }
     if (identical(interfaceMember, 'call')) {
-      listener.propertyGetExitCall(expression.fileOffset, inferredType);
+      listener.propertyGetCall(expression, expression.fileOffset, inferredType);
     } else {
-      listener.propertyGetExit(
-          expression.fileOffset, interfaceMember, inferredType);
+      listener.propertyGet(
+          expression, expression.fileOffset, interfaceMember, inferredType);
     }
     expression.inferredType = inferredType;
   }