Reland "[kernel] Ensure that visitors don't implicitly returns `null`"

This is in preparation to migrate package:kernel to null safety.
For the visitor interfaces to support non-nullable return types, the
implementations must avoid using `null` as return value in its base case.

TEST=Refactoring

Change-Id: Ie8fa5d41b99850d9e4abb59634c72920c64128d9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/183691
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 5bec8c4..4f3ba97 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -23,7 +23,7 @@
 
 import 'src/js_interop.dart';
 
-class JsInteropChecks extends RecursiveVisitor<void> {
+class JsInteropChecks extends RecursiveVisitor {
   final CoreTypes _coreTypes;
   final DiagnosticReporter<Message, LocatedMessage> _diagnosticsReporter;
   final Map<String, Class> _nativeClasses;
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index 337c547..1a91ae1 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -37,7 +37,8 @@
 /// Calling [run] will start the work of visiting the body of the code to
 /// construct a set of inference-nodes that abstractly represent what the code
 /// is doing.
-class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
+class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation>
+    with ir.VisitorNullMixin<TypeInformation> {
   final CompilerOptions _options;
   final JsClosedWorld _closedWorld;
   final InferrerEngine _inferrer;
diff --git a/pkg/compiler/lib/src/ir/debug.dart b/pkg/compiler/lib/src/ir/debug.dart
index 01fc1f0..8e2adfa 100644
--- a/pkg/compiler/lib/src/ir/debug.dart
+++ b/pkg/compiler/lib/src/ir/debug.dart
@@ -11,7 +11,8 @@
 
 import '../util/util.dart' show Indentation, Tagging;
 
-class DebugPrinter extends Visitor with Indentation, Tagging<Node> {
+class DebugPrinter extends Visitor<void>
+    with Indentation, Tagging<Node>, VisitorVoidMixin {
   @override
   StringBuffer sb = new StringBuffer();
 
diff --git a/pkg/compiler/lib/src/ir/scope_visitor.dart b/pkg/compiler/lib/src/ir/scope_visitor.dart
index d2f8225..e5ff326 100644
--- a/pkg/compiler/lib/src/ir/scope_visitor.dart
+++ b/pkg/compiler/lib/src/ir/scope_visitor.dart
@@ -14,7 +14,7 @@
 /// a [VariableScopeModel] that can respond to queries about how a particular
 /// variable is being used at any point in the code.
 class ScopeModelBuilder extends ir.Visitor<EvaluationComplexity>
-    with VariableCollectorMixin {
+    with VariableCollectorMixin, ir.VisitorNullMixin<EvaluationComplexity> {
   final Dart2jsConstantEvaluator _constantEvaluator;
   ir.StaticTypeContext _staticTypeContext;
 
diff --git a/pkg/compiler/lib/src/ir/static_type_base.dart b/pkg/compiler/lib/src/ir/static_type_base.dart
index fe3d62b..67c6014 100644
--- a/pkg/compiler/lib/src/ir/static_type_base.dart
+++ b/pkg/compiler/lib/src/ir/static_type_base.dart
@@ -57,7 +57,8 @@
 /// expression kind. For instance method invocations whose static type depend
 /// on the static types of the receiver and type arguments and the signature
 /// of the targeted procedure.
-abstract class StaticTypeBase extends ir.Visitor<ir.DartType> {
+abstract class StaticTypeBase extends ir.Visitor<ir.DartType>
+    with ir.VisitorNullMixin<ir.DartType> {
   final ir.TypeEnvironment _typeEnvironment;
 
   StaticTypeBase(this._typeEnvironment);
diff --git a/pkg/compiler/lib/src/ir/visitors.dart b/pkg/compiler/lib/src/ir/visitors.dart
index 8d3d497..94db2ae 100644
--- a/pkg/compiler/lib/src/ir/visitors.dart
+++ b/pkg/compiler/lib/src/ir/visitors.dart
@@ -35,6 +35,9 @@
     }
     return null;
   }
+
+  @override
+  String defaultExpression(ir.Expression node) => null;
 }
 
 /// Visitor that converts kernel dart types into [DartType].
@@ -182,6 +185,11 @@
   DartType visitNullType(ir.NullType node) {
     return elementMap.commonElements.nullType;
   }
+
+  @override
+  DartType defaultDartType(ir.DartType node) {
+    throw UnsupportedError('Unsupported type $node (${node.runtimeType})');
+  }
 }
 
 class ConstantValuefier extends ir.ComputeOnceConstantVisitor<ConstantValue> {
diff --git a/pkg/compiler/lib/src/js_model/locals.dart b/pkg/compiler/lib/src/js_model/locals.dart
index 1d5cd00..103c5a8 100644
--- a/pkg/compiler/lib/src/js_model/locals.dart
+++ b/pkg/compiler/lib/src/js_model/locals.dart
@@ -292,7 +292,7 @@
   }
 }
 
-class JumpVisitor extends ir.Visitor {
+class JumpVisitor extends ir.Visitor<void> with ir.VisitorVoidMixin {
   int jumpIndex = 0;
   int labelIndex = 0;
   final MemberEntity member;
diff --git a/pkg/compiler/lib/src/serialization/node_indexer.dart b/pkg/compiler/lib/src/serialization/node_indexer.dart
index edc81ae..52b27ac 100644
--- a/pkg/compiler/lib/src/serialization/node_indexer.dart
+++ b/pkg/compiler/lib/src/serialization/node_indexer.dart
@@ -6,7 +6,8 @@
 
 /// Visitor that ascribes an index to all [ir.TreeNode]s that potentially
 /// needed for serialization and deserialization.
-class _TreeNodeIndexerVisitor extends ir.Visitor<void> {
+class _TreeNodeIndexerVisitor extends ir.Visitor<void>
+    with ir.VisitorVoidMixin {
   int _currentIndex = 0;
   final Map<int, ir.TreeNode> _indexToNodeMap;
   final Map<ir.TreeNode, int> _nodeToIndexMap;
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 4bd37c8..5b4f99f 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -84,7 +84,7 @@
       this.staticTypeProvider);
 }
 
-class KernelSsaGraphBuilder extends ir.Visitor {
+class KernelSsaGraphBuilder extends ir.Visitor<void> with ir.VisitorVoidMixin {
   /// Holds the resulting SSA graph.
   final HGraph graph = new HGraph();
 
@@ -6560,7 +6560,8 @@
   }
 }
 
-class _ErroneousInitializerVisitor extends ir.Visitor<bool> {
+class _ErroneousInitializerVisitor extends ir.Visitor<bool>
+    with ir.VisitorDefaultValueMixin<bool> {
   _ErroneousInitializerVisitor();
 
   // TODO(30809): Use const constructor.
@@ -6580,7 +6581,7 @@
 
   // Expressions: Does the expression always throw?
   @override
-  bool defaultExpression(ir.Expression node) => false;
+  bool get defaultValue => false;
 
   @override
   bool visitThrow(ir.Throw node) => true;
@@ -6839,7 +6840,7 @@
   }
 }
 
-class InlineWeeder extends ir.Visitor {
+class InlineWeeder extends ir.Visitor<void> with ir.VisitorVoidMixin {
   // Invariant: *INSIDE_LOOP* > *OUTSIDE_LOOP*
   static const INLINING_NODES_OUTSIDE_LOOP = 15;
   static const INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR = 3;
@@ -7397,7 +7398,8 @@
 
 /// Visitor to detect environment-rewriting that prevents inlining
 /// (e.g. closures).
-class InlineWeederBodyClosure extends ir.Visitor<void> {
+class InlineWeederBodyClosure extends ir.Visitor<void>
+    with ir.VisitorVoidMixin {
   bool tooDifficult = false;
 
   InlineWeederBodyClosure();
diff --git a/pkg/compiler/lib/src/ssa/kernel_string_builder.dart b/pkg/compiler/lib/src/ssa/kernel_string_builder.dart
index 0d8a57a..b6f69b6 100644
--- a/pkg/compiler/lib/src/ssa/kernel_string_builder.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_string_builder.dart
@@ -10,7 +10,7 @@
 import 'nodes.dart';
 
 /// Visits and concatenates the expressions in a string concatenation.
-class KernelStringBuilder extends ir.Visitor {
+class KernelStringBuilder extends ir.Visitor<void> with ir.VisitorVoidMixin {
   final KernelSsaGraphBuilder builder;
 
   /// The string value generated so far.
diff --git a/pkg/compiler/lib/src/ssa/loop_handler.dart b/pkg/compiler/lib/src/ssa/loop_handler.dart
index 9138b8b..d729fef 100644
--- a/pkg/compiler/lib/src/ssa/loop_handler.dart
+++ b/pkg/compiler/lib/src/ssa/loop_handler.dart
@@ -329,9 +329,10 @@
   int loopKind(ir.TreeNode node) => node.accept(new _KernelLoopTypeVisitor());
 }
 
-class _KernelLoopTypeVisitor extends ir.Visitor<int> {
+class _KernelLoopTypeVisitor extends ir.Visitor<int>
+    with ir.VisitorDefaultValueMixin<int> {
   @override
-  int defaultNode(ir.Node node) => HLoopBlockInformation.NOT_A_LOOP;
+  int get defaultValue => HLoopBlockInformation.NOT_A_LOOP;
 
   @override
   int visitWhileStatement(ir.WhileStatement node) =>
diff --git a/pkg/compiler/lib/src/ssa/switch_continue_analysis.dart b/pkg/compiler/lib/src/ssa/switch_continue_analysis.dart
index 1733898..776a5d5 100644
--- a/pkg/compiler/lib/src/ssa/switch_continue_analysis.dart
+++ b/pkg/compiler/lib/src/ssa/switch_continue_analysis.dart
@@ -7,7 +7,8 @@
 /// Helper class that traverses a kernel AST subtree to see if it has any
 /// continue statements in the body of any switch cases (having continue
 /// statements results in a more complex generated code).
-class SwitchContinueAnalysis extends ir.Visitor<bool> {
+class SwitchContinueAnalysis extends ir.Visitor<bool>
+    with ir.VisitorDefaultValueMixin<bool> {
   SwitchContinueAnalysis._();
 
   static bool containsContinue(ir.Statement switchCaseBody) {
@@ -127,5 +128,5 @@
   }
 
   @override
-  bool defaultNode(ir.Node node) => false;
+  bool get defaultValue => false;
 }
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
index 212601c..58af2ac 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
@@ -36,7 +36,9 @@
         TreeNode,
         TypeParameter,
         VariableDeclaration,
-        Visitor;
+        Visitor,
+        VisitorNullMixin,
+        VisitorVoidMixin;
 
 DiagnosticMessage _createInternalError(Uri uri, int line, int col, String msg) {
   return Message(Code<String>('Expression Compiler Internal error'),
@@ -84,7 +86,7 @@
 /// - locals
 /// - formals
 /// - captured variables (for closures)
-class DartScopeBuilder extends Visitor<void> {
+class DartScopeBuilder extends Visitor<void> with VisitorVoidMixin {
   final Component _component;
   final int _line;
   final int _column;
@@ -196,7 +198,7 @@
 /// that do not have .fileEndOffset field.
 ///
 /// For example - [Block]
-class FileEndOffsetCalculator extends Visitor<int> {
+class FileEndOffsetCalculator extends Visitor<int> with VisitorNullMixin<int> {
   static const int noOffset = -1;
 
   final int _startOffset;
@@ -266,7 +268,7 @@
 /// in the JavaScript scope, so we need to redefine them.
 ///
 /// See [_addSymbolDefinitions]
-class PrivateFieldsVisitor extends Visitor<void> {
+class PrivateFieldsVisitor extends Visitor<void> with VisitorVoidMixin {
   final Map<String, Library> privateFields = {};
 
   @override
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 64eb246..dc76a82 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -332,6 +332,9 @@
     visit(node.body);
     visit(node.finalizer);
   }
+
+  @override
+  void defaultStatement(Statement node) {}
 }
 
 /// Ensures that all of the known DartType implementors are handled.
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index bd952b2..b930366 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -364,7 +364,7 @@
 /// variables that have already been determined to be nullable.
 ///
 // TODO(jmesserly): Introduce flow analysis.
-class _NullableVariableInference extends RecursiveVisitor<void> {
+class _NullableVariableInference extends RecursiveVisitor {
   NullableInference _nullInference;
 
   /// Variables that are currently believed to be not-null.
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index bdcbc1d..81fadbf 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -245,7 +245,7 @@
 /// members can be eliminated, and adjusts the flags to remove those checks.
 ///
 /// See [_CovarianceTransformer.transform].
-class _CovarianceTransformer extends RecursiveVisitor<void> {
+class _CovarianceTransformer extends RecursiveVisitor {
   /// The set of private instance members in [_library] that (potentially) need
   /// covariance checks.
   ///
diff --git a/pkg/dev_compiler/test/expression_compiler/scope_offset_test.dart b/pkg/dev_compiler/test/expression_compiler/scope_offset_test.dart
index 5fa3f1f..413ae5e 100644
--- a/pkg/dev_compiler/test/expression_compiler/scope_offset_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/scope_offset_test.dart
@@ -34,7 +34,7 @@
   });
 }
 
-class ScopeOffsetValidator extends Visitor<void> {
+class ScopeOffsetValidator extends Visitor<void> with VisitorVoidMixin {
   int classCount = 0;
   int memberCount = 0;
   int blockCount = 0;
diff --git a/pkg/dev_compiler/test/nullable_inference_test.dart b/pkg/dev_compiler/test/nullable_inference_test.dart
index e077906..6177a5b 100644
--- a/pkg/dev_compiler/test/nullable_inference_test.dart
+++ b/pkg/dev_compiler/test/nullable_inference_test.dart
@@ -536,7 +536,7 @@
 bool useAnnotations = false;
 NullableInference inference;
 
-class _TestRecursiveVisitor extends RecursiveVisitor<void> {
+class _TestRecursiveVisitor extends RecursiveVisitor {
   final Set<Library> librariesFromDill;
   int _functionNesting = 0;
   TypeEnvironment _typeEnvironment;
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 02b7300..9456de1 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -792,7 +792,7 @@
   }
 }
 
-class ConstantEvaluator extends RecursiveVisitor<Constant> {
+class ConstantEvaluator extends RecursiveResultVisitor<Constant> {
   final ConstantsBackend backend;
   final NumberSemantics numberSemantics;
   ConstantIntFolder intFolder;
diff --git a/pkg/front_end/lib/src/testing/id_extractor.dart b/pkg/front_end/lib/src/testing/id_extractor.dart
index 93af7c6..ebee200 100644
--- a/pkg/front_end/lib/src/testing/id_extractor.dart
+++ b/pkg/front_end/lib/src/testing/id_extractor.dart
@@ -33,7 +33,8 @@
 
 /// Abstract visitor for computing data corresponding to a node or element,
 /// and record it with a generic [Id]
-abstract class DataExtractor<T> extends Visitor with DataRegistry<T> {
+abstract class DataExtractor<T> extends Visitor<void>
+    with VisitorVoidMixin, DataRegistry<T> {
   @override
   final Map<Id, ActualData<T>> actualMap;
 
diff --git a/pkg/front_end/test/comments_on_certain_arguments_tool.dart b/pkg/front_end/test/comments_on_certain_arguments_tool.dart
index d83bf84..9109db8 100644
--- a/pkg/front_end/test/comments_on_certain_arguments_tool.dart
+++ b/pkg/front_end/test/comments_on_certain_arguments_tool.dart
@@ -159,7 +159,7 @@
   return options;
 }
 
-class InvocationVisitor extends RecursiveVisitor<void> {
+class InvocationVisitor extends RecursiveVisitor {
   void visitProcedure(Procedure node) {
     if (node.isNoSuchMethodForwarder) return;
     super.visitProcedure(node);
diff --git a/pkg/front_end/test/fasta/assert_locations_test.dart b/pkg/front_end/test/fasta/assert_locations_test.dart
index c94a1e4..3ef159b 100644
--- a/pkg/front_end/test/fasta/assert_locations_test.dart
+++ b/pkg/front_end/test/fasta/assert_locations_test.dart
@@ -102,7 +102,7 @@
 
 /// Visitor that verifies that all [AssertStatement]s in the Kernel AST
 /// have expected spans for their conditions.
-class VerifyingVisitor extends RecursiveVisitor<Null> {
+class VerifyingVisitor extends RecursiveVisitor {
   final Test test;
 
   /// Set of names of verified [Procedure]s.
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 2b4078a..62858c6 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -109,14 +109,15 @@
         TreeNode,
         UnevaluatedConstant,
         Version,
-        Visitor;
+        Visitor,
+        VisitorVoidMixin;
 
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 
 import 'package:kernel/core_types.dart' show CoreTypes;
 
 import 'package:kernel/kernel.dart'
-    show RecursiveVisitor, loadComponentFromBytes;
+    show RecursiveResultVisitor, loadComponentFromBytes;
 
 import 'package:kernel/reference_from_index.dart' show ReferenceFromIndex;
 
@@ -862,7 +863,7 @@
   }
 }
 
-class StressConstantEvaluatorVisitor extends RecursiveVisitor<Node>
+class StressConstantEvaluatorVisitor extends RecursiveResultVisitor<Node>
     implements ErrorReporter {
   ConstantEvaluator constantEvaluator;
   ConstantEvaluator constantEvaluatorWithEmptyEnvironment;
@@ -1916,7 +1917,7 @@
 /// Visitor that checks that the component has been transformed properly.
 // TODO(johnniwinther): Add checks for all nodes that are unsupported after
 // transformation.
-class VerifyTransformed extends Visitor<void> {
+class VerifyTransformed extends Visitor<void> with VisitorVoidMixin {
   final Target target;
   List<String> errors = [];
 
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_test.dart
index 2891915..bc794f0 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_test.dart
@@ -113,7 +113,7 @@
   }
 }
 
-class _OrdinaryVisitor<R> extends Visitor<R> {
+class _OrdinaryVisitor<R> extends Visitor<R> with VisitorNullMixin<R> {
   final _UnaryFunction<DartType, R> _defaultDartType;
 
   _OrdinaryVisitor({_UnaryFunction<DartType, R> defaultDartType})
@@ -129,7 +129,7 @@
   }
 }
 
-class _TypeSchemaVisitor<R> extends Visitor<R> {
+class _TypeSchemaVisitor<R> extends Visitor<R> with VisitorNullMixin<R> {
   final _UnaryFunction<DartType, R> _defaultDartType;
   final _UnaryFunction<UnknownType, R> _visitUnknownType;
 
diff --git a/pkg/front_end/test/static_types/analysis_helper.dart b/pkg/front_end/test/static_types/analysis_helper.dart
index 539d58e..fcd3b9f 100644
--- a/pkg/front_end/test/static_types/analysis_helper.dart
+++ b/pkg/front_end/test/static_types/analysis_helper.dart
@@ -42,7 +42,7 @@
       .run(verbose: verbose, generate: generate);
 }
 
-class StaticTypeVisitorBase extends RecursiveVisitor<void> {
+class StaticTypeVisitorBase extends RecursiveVisitor {
   final TypeEnvironment typeEnvironment;
 
   StaticTypeContext staticTypeContext;
diff --git a/pkg/frontend_server/lib/src/to_string_transformer.dart b/pkg/frontend_server/lib/src/to_string_transformer.dart
index 8969e51..9942dd4 100644
--- a/pkg/frontend_server/lib/src/to_string_transformer.dart
+++ b/pkg/frontend_server/lib/src/to_string_transformer.dart
@@ -11,7 +11,7 @@
 
 /// A [RecursiveVisitor] that replaces [Object.toString] overrides with
 /// `super.toString()`.
-class ToStringVisitor extends RecursiveVisitor<void> {
+class ToStringVisitor extends RecursiveVisitor {
   /// The [packageUris] must not be null.
   ToStringVisitor(this._packageUris) : assert(_packageUris != null);
 
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 25c299b..821b2f9 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -2711,7 +2711,7 @@
   int operator [](SwitchCase node) => index[node];
 }
 
-class ConstantIndexer extends RecursiveVisitor {
+class ConstantIndexer extends RecursiveResultVisitor {
   final StringIndexer stringIndexer;
 
   final List<Constant> entries = <Constant>[];
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index 272679f..c8353fa 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -74,35 +74,35 @@
   }
 }
 
-class OccurrenceCollectorVisitor extends DartTypeVisitor {
+class OccurrenceCollectorVisitor extends DartTypeVisitor<void> {
   final Set<TypeParameter> typeParameters;
   Set<TypeParameter> occurred = new Set<TypeParameter>();
 
   OccurrenceCollectorVisitor(this.typeParameters);
 
-  visit(DartType node) => node.accept(this);
+  void visit(DartType node) => node.accept(this);
 
-  visitNamedType(NamedType node) {
+  void visitNamedType(NamedType node) {
     node.type.accept(this);
   }
 
-  visitInvalidType(InvalidType node);
-  visitDynamicType(DynamicType node);
-  visitVoidType(VoidType node);
+  void visitInvalidType(InvalidType node);
+  void visitDynamicType(DynamicType node);
+  void visitVoidType(VoidType node);
 
-  visitInterfaceType(InterfaceType node) {
+  void visitInterfaceType(InterfaceType node) {
     for (DartType argument in node.typeArguments) {
       argument.accept(this);
     }
   }
 
-  visitTypedefType(TypedefType node) {
+  void visitTypedefType(TypedefType node) {
     for (DartType argument in node.typeArguments) {
       argument.accept(this);
     }
   }
 
-  visitFunctionType(FunctionType node) {
+  void visitFunctionType(FunctionType node) {
     for (TypeParameter typeParameter in node.typeParameters) {
       typeParameter.bound.accept(this);
       typeParameter.defaultType?.accept(this);
@@ -116,11 +116,14 @@
     node.returnType.accept(this);
   }
 
-  visitTypeParameterType(TypeParameterType node) {
+  void visitTypeParameterType(TypeParameterType node) {
     if (typeParameters.contains(node.parameter)) {
       occurred.add(node.parameter);
     }
   }
+
+  @override
+  void defaultDartType(DartType node) {}
 }
 
 DartType instantiateToBounds(
diff --git a/pkg/kernel/lib/src/tool/find_referenced_libraries.dart b/pkg/kernel/lib/src/tool/find_referenced_libraries.dart
index 73733ca..9988f13 100644
--- a/pkg/kernel/lib/src/tool/find_referenced_libraries.dart
+++ b/pkg/kernel/lib/src/tool/find_referenced_libraries.dart
@@ -23,10 +23,10 @@
   return false;
 }
 
-class _LibraryCollector extends RecursiveVisitor<Null> {
+class _LibraryCollector extends RecursiveVisitor {
   Set<Library> allSeenLibraries = {};
 
-  Null defaultNode(Node node) {
+  void defaultNode(Node node) {
     if (node is NamedNode) {
       // Named nodes can be linked to.
       seen(node);
@@ -38,7 +38,7 @@
     super.defaultNode(node);
   }
 
-  Null defaultMemberReference(Member node) {
+  void defaultMemberReference(Member node) {
     seen(node);
     super.defaultMemberReference(node);
   }
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index a7faeea..26699f0 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -29,7 +29,7 @@
   NormalNamer(this.prefix);
 }
 
-class ConstantNamer extends RecursiveVisitor<Null> with Namer<Constant> {
+class ConstantNamer extends RecursiveResultVisitor<Null> with Namer<Constant> {
   final String prefix;
   ConstantNamer(this.prefix);
 
@@ -271,7 +271,7 @@
 }
 
 /// A quick and dirty ambiguous text printer.
-class Printer extends Visitor<Null> {
+class Printer extends Visitor<void> with VisitorVoidMixin {
   final NameSystem syntheticNames;
   final StringSink sink;
   final Annotator annotator;
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index f3b00a1..3ababf6 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -107,6 +107,12 @@
   String visitLoadLibrary(LoadLibrary _) => "load";
   String visitConstantExpression(ConstantExpression _) => "const";
   String visitInstanceCreation(InstanceCreation _) => "object";
+
+  @override
+  String defaultExpression(Expression node) {
+    throw new UnimplementedError(
+        'Unimplemented expression $node (${node.runtimeType})');
+  }
 }
 
 const TextSerializer<InvalidExpression> invalidExpressionSerializer =
@@ -846,6 +852,11 @@
   String visitTypedefType(TypedefType _) => "typedef";
   String visitFutureOrType(FutureOrType _) => "futureor";
   String visitNullType(NullType _) => "null-type";
+
+  @override
+  String defaultDartType(DartType node) {
+    throw UnimplementedError('Unimplemented type $node (${node.runtimeType})');
+  }
 }
 
 const TextSerializer<InvalidType> invalidTypeSerializer =
@@ -1031,6 +1042,12 @@
   String visitContinueSwitchStatement(ContinueSwitchStatement node) =>
       "continue";
   String visitFunctionDeclaration(FunctionDeclaration node) => "local-fun";
+
+  @override
+  String defaultStatement(Statement node) {
+    throw new UnimplementedError(
+        "Unimplemented statement $node (${node.runtimeType})");
+  }
 }
 
 TextSerializer<ExpressionStatement> expressionStatementSerializer = new Wrapped(
@@ -1795,6 +1812,12 @@
   String visitTearOffConstant(TearOffConstant node) => "const-tearoff";
   String visitTypeLiteralConstant(TypeLiteralConstant node) => "const-type";
   String visitUnevaluatedConstant(UnevaluatedConstant node) => "const-expr";
+
+  @override
+  String defaultConstant(Constant node) {
+    throw new UnimplementedError(
+        'Unimplemented constant $node (${node.runtimeType})');
+  }
 }
 
 TextSerializer<BoolConstant> boolConstantSerializer =
diff --git a/pkg/kernel/lib/transformations/scanner.dart b/pkg/kernel/lib/transformations/scanner.dart
index 5aac0a8..ee9b660 100644
--- a/pkg/kernel/lib/transformations/scanner.dart
+++ b/pkg/kernel/lib/transformations/scanner.dart
@@ -218,7 +218,7 @@
 }
 
 abstract class ExpressionScanner<Y extends TreeNode>
-    extends RecursiveVisitor<void> implements Scanner<Expression, Y> {
+    extends RecursiveResultVisitor<void> implements Scanner<Expression, Y> {
   final Scanner<Y, TreeNode> next;
   ScanResult<Expression, Y> _result;
 
@@ -242,7 +242,7 @@
 }
 
 abstract class MethodInvocationScanner<Y extends TreeNode>
-    extends RecursiveVisitor<void> implements Scanner<MethodInvocation, Y> {
+    extends RecursiveVisitor implements Scanner<MethodInvocation, Y> {
   final Scanner<Y, TreeNode> next;
   ScanResult<MethodInvocation, Y> _result;
 
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index cdd2f22..00dc2af 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -48,7 +48,7 @@
 /// Checks that a kernel component is well-formed.
 ///
 /// This does not include any kind of type checking.
-class VerifyingVisitor extends RecursiveVisitor<void> {
+class VerifyingVisitor extends RecursiveResultVisitor<void> {
   final Set<Class> classes = new Set<Class>();
   final Set<Typedef> typedefs = new Set<Typedef>();
   Set<TypeParameter> typeParametersInScope = new Set<TypeParameter>();
@@ -883,14 +883,14 @@
       : _staticTypeContext = new StatefulStaticTypeContext.stacked(env);
 
   @override
-  visitLibrary(Library node) {
+  void visitLibrary(Library node) {
     _staticTypeContext.enterLibrary(node);
     super.visitLibrary(node);
     _staticTypeContext.leaveLibrary(node);
   }
 
   @override
-  visitField(Field node) {
+  void visitField(Field node) {
     currentMember = node;
     _staticTypeContext.enterMember(node);
     super.visitField(node);
@@ -899,7 +899,7 @@
   }
 
   @override
-  visitProcedure(Procedure node) {
+  void visitProcedure(Procedure node) {
     currentMember = node;
     _staticTypeContext.enterMember(node);
     super.visitProcedure(node);
@@ -908,7 +908,7 @@
   }
 
   @override
-  visitConstructor(Constructor node) {
+  void visitConstructor(Constructor node) {
     currentMember = node;
     _staticTypeContext.enterMember(node);
     super.visitConstructor(node);
@@ -917,7 +917,7 @@
   }
 
   @override
-  defaultExpression(Expression node) {
+  void defaultExpression(Expression node) {
     try {
       node.getStaticType(_staticTypeContext);
     } catch (_) {
@@ -929,7 +929,7 @@
   }
 }
 
-class CheckParentPointers extends Visitor {
+class CheckParentPointers extends Visitor<void> with VisitorVoidMixin {
   static void check(TreeNode node) {
     node.accept(new CheckParentPointers(node.parent));
   }
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index fefa970..4ef6055 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -14,7 +14,7 @@
 abstract class ExpressionVisitor<R> {
   const ExpressionVisitor();
 
-  R defaultExpression(Expression node) => null;
+  R defaultExpression(Expression node);
   R defaultBasicLiteral(BasicLiteral node) => defaultExpression(node);
 
   R visitInvalidExpression(InvalidExpression node) => defaultExpression(node);
@@ -87,7 +87,7 @@
 abstract class StatementVisitor<R> {
   const StatementVisitor();
 
-  R defaultStatement(Statement node) => null;
+  R defaultStatement(Statement node);
 
   R visitExpressionStatement(ExpressionStatement node) =>
       defaultStatement(node);
@@ -118,7 +118,7 @@
 abstract class MemberVisitor<R> {
   const MemberVisitor();
 
-  R defaultMember(Member node) => null;
+  R defaultMember(Member node);
 
   R visitConstructor(Constructor node) => defaultMember(node);
   R visitProcedure(Procedure node) => defaultMember(node);
@@ -131,7 +131,7 @@
 abstract class InitializerVisitor<R> {
   const InitializerVisitor();
 
-  R defaultInitializer(Initializer node) => null;
+  R defaultInitializer(Initializer node);
 
   R visitInvalidInitializer(InvalidInitializer node) =>
       defaultInitializer(node);
@@ -143,7 +143,7 @@
   R visitAssertInitializer(AssertInitializer node) => defaultInitializer(node);
 }
 
-class TreeVisitor<R>
+abstract class TreeVisitor<R>
     implements
         ExpressionVisitor<R>,
         StatementVisitor<R>,
@@ -151,7 +151,7 @@
         InitializerVisitor<R> {
   const TreeVisitor();
 
-  R defaultTreeNode(TreeNode node) => null;
+  R defaultTreeNode(TreeNode node);
 
   // Expressions
   R defaultExpression(Expression node) => defaultTreeNode(node);
@@ -289,10 +289,10 @@
   R visitComponent(Component node) => defaultTreeNode(node);
 }
 
-class DartTypeVisitor<R> {
+abstract class DartTypeVisitor<R> {
   const DartTypeVisitor();
 
-  R defaultDartType(DartType node) => null;
+  R defaultDartType(DartType node);
 
   R visitInvalidType(InvalidType node) => defaultDartType(node);
   R visitDynamicType(DynamicType node) => defaultDartType(node);
@@ -307,8 +307,8 @@
   R visitNullType(NullType node) => defaultDartType(node);
 }
 
-class DartTypeVisitor1<R, T> {
-  R defaultDartType(DartType node, T arg) => null;
+abstract class DartTypeVisitor1<R, T> {
+  R defaultDartType(DartType node, T arg);
 
   R visitInvalidType(InvalidType node, T arg) => defaultDartType(node, arg);
   R visitDynamicType(DynamicType node, T arg) => defaultDartType(node, arg);
@@ -332,10 +332,10 @@
 ///
 /// Use [ComputeOnceConstantVisitor] or [VisitOnceConstantVisitor] to visit
 /// a constant node while ensuring each subnode is only visited once.
-class ConstantVisitor<R> {
+abstract class ConstantVisitor<R> {
   const ConstantVisitor();
 
-  R defaultConstant(Constant node) => null;
+  R defaultConstant(Constant node);
 
   R visitNullConstant(NullConstant node) => defaultConstant(node);
   R visitBoolConstant(BoolConstant node) => defaultConstant(node);
@@ -435,7 +435,7 @@
 /// Visitor-like class used for visiting a [Constant] node while computing a
 /// value for each subnode. The visitor caches the computed values ensuring that
 /// each subnode is only visited once.
-class ComputeOnceConstantVisitor<R> implements _ConstantCallback<R> {
+abstract class ComputeOnceConstantVisitor<R> implements _ConstantCallback<R> {
   _ConstantCallbackVisitor<R> _visitor;
   Map<Constant, R> cache = new LinkedHashMap.identity();
 
@@ -461,7 +461,7 @@
     return value;
   }
 
-  R defaultConstant(Constant node) => null;
+  R defaultConstant(Constant node);
 
   R visitNullConstant(NullConstant node) => defaultConstant(node);
   R visitBoolConstant(BoolConstant node) => defaultConstant(node);
@@ -484,7 +484,7 @@
 ///
 /// The visitor records the visited node to ensure that each subnode is only
 /// visited once.
-class VisitOnceConstantVisitor implements _ConstantCallback<void> {
+abstract class VisitOnceConstantVisitor implements _ConstantCallback<void> {
   _ConstantCallbackVisitor<void> _visitor;
   Set<Constant> cache = new LinkedHashSet.identity();
 
@@ -502,7 +502,7 @@
     }
   }
 
-  void defaultConstant(Constant node) => null;
+  void defaultConstant(Constant node);
 
   void visitNullConstant(NullConstant node) => defaultConstant(node);
   void visitBoolConstant(BoolConstant node) => defaultConstant(node);
@@ -523,10 +523,10 @@
       defaultConstant(node);
 }
 
-class MemberReferenceVisitor<R> {
+abstract class MemberReferenceVisitor<R> {
   const MemberReferenceVisitor();
 
-  R defaultMemberReference(Member node) => null;
+  R defaultMemberReference(Member node);
 
   R visitFieldReference(Field node) => defaultMemberReference(node);
   R visitConstructorReference(Constructor node) => defaultMemberReference(node);
@@ -537,7 +537,7 @@
   }
 }
 
-class Visitor<R> extends TreeVisitor<R>
+abstract class Visitor<R> extends TreeVisitor<R>
     implements
         DartTypeVisitor<R>,
         ConstantVisitor<R>,
@@ -545,7 +545,7 @@
   const Visitor();
 
   /// The catch-all case, except for references.
-  R defaultNode(Node node) => null;
+  R defaultNode(Node node);
   R defaultTreeNode(TreeNode node) => defaultNode(node);
 
   // DartTypes
@@ -581,11 +581,13 @@
   R visitUnevaluatedConstant(UnevaluatedConstant node) => defaultConstant(node);
 
   // Class references
-  R visitClassReference(Class node) => null;
-  R visitTypedefReference(Typedef node) => null;
+  R visitClassReference(Class node);
+
+  R visitTypedefReference(Typedef node);
 
   // Constant references
-  R defaultConstantReference(Constant node) => null;
+  R defaultConstantReference(Constant node);
+
   R visitNullConstantReference(NullConstant node) =>
       defaultConstantReference(node);
   R visitBoolConstantReference(BoolConstant node) =>
@@ -617,7 +619,8 @@
       defaultConstantReference(node);
 
   // Member references
-  R defaultMemberReference(Member node) => null;
+  R defaultMemberReference(Member node);
+
   R visitFieldReference(Field node) => defaultMemberReference(node);
   R visitConstructorReference(Constructor node) => defaultMemberReference(node);
   R visitProcedureReference(Procedure node) => defaultMemberReference(node);
@@ -631,9 +634,117 @@
   R visitNamedType(NamedType node) => defaultNode(node);
 }
 
-class RecursiveVisitor<R> extends Visitor<R> {
+/// Visitor mixin that throws as its base case.
+mixin VisitorThrowingMixin<R> implements Visitor<R> {
+  @override
+  R defaultNode(Node node) {
+    throw new UnimplementedError('Unimplemented ${runtimeType}.defaultNode for '
+        '${node} (${node.runtimeType})');
+  }
+
+  @override
+  R visitClassReference(Class node) {
+    throw new UnimplementedError(
+        'Unimplemented ${runtimeType}.visitClassReference for '
+        '${node} (${node.runtimeType})');
+  }
+
+  @override
+  R visitTypedefReference(Typedef node) {
+    throw new UnimplementedError(
+        'Unimplemented ${runtimeType}.visitTypedefReference for '
+        '${node} (${node.runtimeType})');
+  }
+
+  @override
+  R defaultConstantReference(Constant node) {
+    throw new UnimplementedError(
+        'Unimplemented ${runtimeType}.defaultConstantReference for '
+        '${node} (${node.runtimeType})');
+  }
+
+  @override
+  R defaultMemberReference(Member node) {
+    throw new UnimplementedError(
+        'Unimplemented ${runtimeType}.defaultMemberReference for '
+        '${node} (${node.runtimeType})');
+  }
+}
+
+/// Visitor mixin that returns a value of type [R] or `null` and uses `null` as
+/// its base case.
+mixin VisitorNullMixin<R> implements Visitor<R /*?*/ > {
+  @override
+  R defaultNode(Node node) => null;
+
+  @override
+  R visitClassReference(Class node) => null;
+
+  @override
+  R visitTypedefReference(Typedef node) => null;
+
+  @override
+  R defaultConstantReference(Constant node) => null;
+
+  @override
+  R defaultMemberReference(Member node) => null;
+}
+
+/// Visitor mixin that returns void.
+mixin VisitorVoidMixin implements Visitor<void> {
+  @override
+  void defaultNode(Node node) {}
+
+  @override
+  void visitClassReference(Class node) {}
+
+  @override
+  void visitTypedefReference(Typedef node) {}
+
+  @override
+  void defaultConstantReference(Constant node) {}
+
+  @override
+  void defaultMemberReference(Member node) {}
+}
+
+/// Visitor mixin that returns a [defaultValue] of type [R] as its base case.
+mixin VisitorDefaultValueMixin<R> implements Visitor<R> {
+  R get defaultValue;
+
+  @override
+  R defaultNode(Node node) => defaultValue;
+
+  @override
+  R visitClassReference(Class node) => defaultValue;
+
+  @override
+  R visitTypedefReference(Typedef node) => defaultValue;
+
+  @override
+  R defaultConstantReference(Constant node) => defaultValue;
+
+  @override
+  R defaultMemberReference(Member node) => defaultValue;
+}
+
+/// Recursive visitor that doesn't return anything from its visit methods.
+// TODO(johnniwinther): Remove type parameter when all subclasses have been
+// changed to use [RecursiveVisitor] without type arguments.
+class RecursiveVisitor<T> extends Visitor<void> with VisitorVoidMixin {
   const RecursiveVisitor();
 
+  void defaultNode(Node node) {
+    node.visitChildren(this);
+  }
+}
+
+/// Recursive visitor that returns a result of type [R] or `null` from its
+/// visit methods.
+class RecursiveResultVisitor<R> extends Visitor<R /*?*/ >
+    with VisitorNullMixin<R> {
+  const RecursiveResultVisitor();
+
   R defaultNode(Node node) {
     node.visitChildren(this);
     return null;
@@ -685,7 +796,7 @@
 abstract class ExpressionVisitor1<R, T> {
   const ExpressionVisitor1();
 
-  R defaultExpression(Expression node, T arg) => null;
+  R defaultExpression(Expression node, T arg);
   R defaultBasicLiteral(BasicLiteral node, T arg) =>
       defaultExpression(node, arg);
   R visitInvalidExpression(InvalidExpression node, T arg) =>
@@ -784,7 +895,7 @@
 abstract class StatementVisitor1<R, T> {
   const StatementVisitor1();
 
-  R defaultStatement(Statement node, T arg) => null;
+  R defaultStatement(Statement node, T arg);
 
   R visitExpressionStatement(ExpressionStatement node, T arg) =>
       defaultStatement(node, arg);
@@ -825,7 +936,7 @@
     implements StatementVisitor1<R, T> {
   const BodyVisitor1();
 
-  R defaultStatement(Statement node, T arg) => null;
+  R defaultStatement(Statement node, T arg);
   R visitExpressionStatement(ExpressionStatement node, T arg) =>
       defaultStatement(node, arg);
   R visitBlock(Block node, T arg) => defaultStatement(node, arg);
diff --git a/pkg/kernel/test/metadata_test.dart b/pkg/kernel/test/metadata_test.dart
index 377ad22..d1214b6 100644
--- a/pkg/kernel/test/metadata_test.dart
+++ b/pkg/kernel/test/metadata_test.dart
@@ -96,7 +96,7 @@
 
 /// Visitor calling [handle] function on every node which can have metadata
 /// associated with it and also satisfies the given [predicate].
-class Visitor extends RecursiveVisitor<Null> {
+class Visitor extends RecursiveVisitor {
   final NodePredicate predicate;
   final void Function(TreeNode) handle;
 
diff --git a/pkg/vm/lib/transformations/call_site_annotator.dart b/pkg/vm/lib/transformations/call_site_annotator.dart
index 324401f..8a45c5a 100644
--- a/pkg/vm/lib/transformations/call_site_annotator.dart
+++ b/pkg/vm/lib/transformations/call_site_annotator.dart
@@ -30,7 +30,7 @@
   libraries.forEach(transformer.visitLibrary);
 }
 
-class AnnotateWithStaticTypes extends RecursiveVisitor<Null> {
+class AnnotateWithStaticTypes extends RecursiveVisitor {
   final CallSiteAttributesMetadataRepository _metadata;
   final TypeEnvironment env;
   StaticTypeContext _staticTypeContext;
diff --git a/pkg/vm/lib/transformations/devirtualization.dart b/pkg/vm/lib/transformations/devirtualization.dart
index acbfa39..a81d089 100644
--- a/pkg/vm/lib/transformations/devirtualization.dart
+++ b/pkg/vm/lib/transformations/devirtualization.dart
@@ -27,7 +27,7 @@
 /// Subclasses should implement particular devirtualization strategy in
 /// [getDirectCall] method. Once direct target is determined, the invocation
 /// node is annotated with direct call metadata.
-abstract class Devirtualization extends RecursiveVisitor<Null> {
+abstract class Devirtualization extends RecursiveVisitor {
   /// Toggles tracing (useful for debugging).
   static const _trace = const bool.fromEnvironment('trace.devirtualization');
 
diff --git a/pkg/vm/lib/transformations/mixin_deduplication.dart b/pkg/vm/lib/transformations/mixin_deduplication.dart
index 7f76626..31481a8 100644
--- a/pkg/vm/lib/transformations/mixin_deduplication.dart
+++ b/pkg/vm/lib/transformations/mixin_deduplication.dart
@@ -153,7 +153,7 @@
 
 /// Rewrites references to the deduplicated mixin application
 /// classes. Updates interface targets and types.
-class ReferenceUpdater extends RecursiveVisitor<void> {
+class ReferenceUpdater extends RecursiveVisitor {
   final DeduplicateMixinsTransformer transformer;
   final _visitedConstants = new Set<Constant>.identity();
 
diff --git a/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart b/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
index e838c80..9b7e27c 100644
--- a/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
+++ b/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
@@ -149,7 +149,7 @@
   }
 }
 
-class DynamicSelectorsCollector extends RecursiveVisitor<Null> {
+class DynamicSelectorsCollector extends RecursiveVisitor {
   final Set<Selector> dynamicSelectors = new Set<Selector>();
   final Set<Selector> nonThisSelectors = new Set<Selector>();
   final Set<Selector> tearOffSelectors = new Set<Selector>();
diff --git a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
index 4adf6c6..20a0412 100644
--- a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
+++ b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
@@ -198,7 +198,7 @@
   }
 }
 
-class _Collect extends RecursiveVisitor<void> {
+class _Collect extends RecursiveVisitor {
   final SignatureShaker shaker;
 
   /// Parameters of the current function.
@@ -332,7 +332,7 @@
   }
 }
 
-class _Transform extends RecursiveVisitor<void> {
+class _Transform extends RecursiveVisitor {
   final SignatureShaker shaker;
 
   StaticTypeContext typeContext;
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 789d1e1..aed40a03 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -308,7 +308,7 @@
 
 /// Collects sets of captured variables, as well as variables
 /// modified in loops and try blocks.
-class _VariablesInfoCollector extends RecursiveVisitor<Null> {
+class _VariablesInfoCollector extends RecursiveVisitor {
   /// Maps declared variables to their declaration index.
   final Map<VariableDeclaration, int> varIndex = <VariableDeclaration, int>{};
 
@@ -514,7 +514,7 @@
 enum FieldSummaryType { kFieldGuard, kInitializer }
 
 /// Create a type flow summary for a member from the kernel AST.
-class SummaryCollector extends RecursiveVisitor<TypeExpr> {
+class SummaryCollector extends RecursiveResultVisitor<TypeExpr> {
   final Target target;
   final TypeEnvironment _environment;
   final ClosedWorldClassHierarchy _hierarchy;
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index b8b187c..ba36509 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -144,7 +144,7 @@
 }
 
 /// Annotates kernel AST with metadata using results of type flow analysis.
-class AnnotateKernel extends RecursiveVisitor<Null> {
+class AnnotateKernel extends RecursiveVisitor {
   final TypeFlowAnalysis _typeFlowAnalysis;
   final FieldMorpher fieldMorpher;
   final DirectCallMetadataRepository _directCallMetadataRepository;
@@ -741,7 +741,7 @@
 /// Visits Dart types and collects all classes and typedefs used in types.
 /// This visitor is used during pass 1 of tree shaking. It is a separate
 /// visitor because [Transformer] does not provide a way to traverse types.
-class _TreeShakerTypeVisitor extends RecursiveVisitor<Null> {
+class _TreeShakerTypeVisitor extends RecursiveVisitor {
   final TreeShaker shaker;
 
   _TreeShakerTypeVisitor(this.shaker);
diff --git a/pkg/vm/test/incremental_compiler_test.dart b/pkg/vm/test/incremental_compiler_test.dart
index 179c37b..2fc1928 100644
--- a/pkg/vm/test/incremental_compiler_test.dart
+++ b/pkg/vm/test/incremental_compiler_test.dart
@@ -1618,7 +1618,7 @@
   await sink.close();
 }
 
-class LibraryReferenceCollector extends RecursiveVisitor<void> {
+class LibraryReferenceCollector extends RecursiveVisitor {
   Set<Library> librariesReferenced = {};
 
   void defaultMemberReference(Member node) {
diff --git a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
index 1e63109..a046634 100644
--- a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
+++ b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
@@ -61,7 +61,7 @@
   void recordTearOff(Procedure target) {}
 }
 
-class PrintSummaries extends RecursiveVisitor<Null> {
+class PrintSummaries extends RecursiveVisitor {
   SummaryCollector _summaryCollector;
   final StringBuffer _buf = new StringBuffer();