Version 2.13.0-46.0.dev

Merge commit 'f0ec362a1c082bf9c29e805f1bf7981d38eff8a9' into 'dev'
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 95ce3fd..04edcc1 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -482,7 +482,7 @@
   FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS,
   FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS,
   FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_WITH,
-  HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR,
+  HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER,
   HintCode.ASSIGNMENT_OF_DO_NOT_STORE,
   HintCode.CAN_BE_NULL_AFTER_NULL_AWARE,
   HintCode.DEAD_CODE,
diff --git a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
index 030cecb..69ebea3 100644
--- a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
@@ -16,6 +16,7 @@
   EnableString.control_flow_collections:
       ExperimentalFeatures.control_flow_collections,
   EnableString.extension_methods: ExperimentalFeatures.extension_methods,
+  EnableString.extension_types: ExperimentalFeatures.extension_types,
   EnableString.generic_metadata: ExperimentalFeatures.generic_metadata,
   EnableString.non_nullable: ExperimentalFeatures.non_nullable,
   EnableString.nonfunction_type_aliases:
@@ -39,6 +40,9 @@
   /// String to enable the experiment "extension-methods"
   static const String extension_methods = 'extension-methods';
 
+  /// String to enable the experiment "extension-types"
+  static const String extension_types = 'extension-types';
+
   /// String to enable the experiment "generic-metadata"
   static const String generic_metadata = 'generic-metadata';
 
@@ -95,8 +99,18 @@
     releaseVersion: Version.parse('2.6.0'),
   );
 
-  static final generic_metadata = ExperimentalFeature(
+  static final extension_types = ExperimentalFeature(
     index: 3,
+    enableString: EnableString.extension_types,
+    isEnabledByDefault: IsEnabledByDefault.extension_types,
+    isExpired: IsExpired.extension_types,
+    documentation: 'Extension Types',
+    experimentalReleaseVersion: null,
+    releaseVersion: Version.parse('2.13.0'),
+  );
+
+  static final generic_metadata = ExperimentalFeature(
+    index: 4,
     enableString: EnableString.generic_metadata,
     isEnabledByDefault: IsEnabledByDefault.generic_metadata,
     isExpired: IsExpired.generic_metadata,
@@ -107,7 +121,7 @@
   );
 
   static final non_nullable = ExperimentalFeature(
-    index: 4,
+    index: 5,
     enableString: EnableString.non_nullable,
     isEnabledByDefault: IsEnabledByDefault.non_nullable,
     isExpired: IsExpired.non_nullable,
@@ -117,7 +131,7 @@
   );
 
   static final nonfunction_type_aliases = ExperimentalFeature(
-    index: 5,
+    index: 6,
     enableString: EnableString.nonfunction_type_aliases,
     isEnabledByDefault: IsEnabledByDefault.nonfunction_type_aliases,
     isExpired: IsExpired.nonfunction_type_aliases,
@@ -127,7 +141,7 @@
   );
 
   static final set_literals = ExperimentalFeature(
-    index: 6,
+    index: 7,
     enableString: EnableString.set_literals,
     isEnabledByDefault: IsEnabledByDefault.set_literals,
     isExpired: IsExpired.set_literals,
@@ -137,7 +151,7 @@
   );
 
   static final spread_collections = ExperimentalFeature(
-    index: 7,
+    index: 8,
     enableString: EnableString.spread_collections,
     isEnabledByDefault: IsEnabledByDefault.spread_collections,
     isExpired: IsExpired.spread_collections,
@@ -147,7 +161,7 @@
   );
 
   static final triple_shift = ExperimentalFeature(
-    index: 8,
+    index: 9,
     enableString: EnableString.triple_shift,
     isEnabledByDefault: IsEnabledByDefault.triple_shift,
     isExpired: IsExpired.triple_shift,
@@ -157,7 +171,7 @@
   );
 
   static final value_class = ExperimentalFeature(
-    index: 9,
+    index: 10,
     enableString: EnableString.value_class,
     isEnabledByDefault: IsEnabledByDefault.value_class,
     isExpired: IsExpired.value_class,
@@ -167,7 +181,7 @@
   );
 
   static final variance = ExperimentalFeature(
-    index: 10,
+    index: 11,
     enableString: EnableString.variance,
     isEnabledByDefault: IsEnabledByDefault.variance,
     isExpired: IsExpired.variance,
@@ -189,6 +203,9 @@
   /// Default state of the experiment "extension-methods"
   static const bool extension_methods = true;
 
+  /// Default state of the experiment "extension-types"
+  static const bool extension_types = true;
+
   /// Default state of the experiment "generic-metadata"
   static const bool generic_metadata = false;
 
@@ -227,6 +244,9 @@
   /// Expiration status of the experiment "extension-methods"
   static const bool extension_methods = false;
 
+  /// Expiration status of the experiment "extension-types"
+  static const bool extension_types = false;
+
   /// Expiration status of the experiment "generic-metadata"
   static const bool generic_metadata = false;
 
@@ -265,6 +285,9 @@
   bool get extension_methods =>
       isEnabled(ExperimentalFeatures.extension_methods);
 
+  /// Current state for the flag "extension-types"
+  bool get extension_types => isEnabled(ExperimentalFeatures.extension_types);
+
   /// Current state for the flag "generic-metadata"
   bool get generic_metadata => isEnabled(ExperimentalFeatures.generic_metadata);
 
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 7049407..3621e3b 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -19,9 +19,9 @@
    * 0: the name of the actual argument type
    * 1: the name of the expected function return type
    */
-  static const HintCode ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR =
+  static const HintCode ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER =
       HintCode(
-          'ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR',
+          'ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER',
           "The argument type '{0}' can't be assigned to the parameter type "
               "'{1} Function(Object)' or '{1} Function(Object, StackTrace)'.");
 
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index b3136ff..9b54f4e 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -23,9 +23,9 @@
 import 'package:analyzer/src/dart/resolver/body_inference_context.dart';
 import 'package:analyzer/src/dart/resolver/exit_detector.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
-import 'package:analyzer/src/error/catch_error_verifier.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/error/deprecated_member_use_verifier.dart';
+import 'package:analyzer/src/error/error_handler_verifier.dart';
 import 'package:analyzer/src/error/must_call_super_verifier.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -70,7 +70,7 @@
 
   final MustCallSuperVerifier _mustCallSuperVerifier;
 
-  final CatchErrorVerifier _catchErrorVerifier;
+  final ErrorHandlerVerifier _errorHandlerVerifier;
 
   /// The [WorkspacePackage] in which [_currentLibrary] is declared.
   final WorkspacePackage? _workspacePackage;
@@ -109,8 +109,8 @@
         _deprecatedVerifier =
             DeprecatedMemberUseVerifier(workspacePackage, _errorReporter),
         _mustCallSuperVerifier = MustCallSuperVerifier(_errorReporter),
-        _catchErrorVerifier =
-            CatchErrorVerifier(_errorReporter, typeProvider, typeSystem),
+        _errorHandlerVerifier =
+            ErrorHandlerVerifier(_errorReporter, typeProvider, typeSystem),
         _workspacePackage = workspacePackage {
     _deprecatedVerifier.pushInDeprecatedValue(_currentLibrary.hasDeprecated);
     _inDoNotStoreMember = _currentLibrary.hasDoNotStore;
@@ -596,7 +596,7 @@
   void visitMethodInvocation(MethodInvocation node) {
     _deprecatedVerifier.methodInvocation(node);
     _checkForNullAwareHints(node, node.operator);
-    _catchErrorVerifier.verifyMethodInvocation(node);
+    _errorHandlerVerifier.verifyMethodInvocation(node);
     super.visitMethodInvocation(node);
   }
 
diff --git a/pkg/analyzer/lib/src/error/catch_error_verifier.dart b/pkg/analyzer/lib/src/error/catch_error_verifier.dart
deleted file mode 100644
index 00d227d..0000000
--- a/pkg/analyzer/lib/src/error/catch_error_verifier.dart
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/visitor.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/error/listener.dart';
-import 'package:analyzer/src/dart/ast/extensions.dart';
-import 'package:analyzer/src/dart/element/type_provider.dart';
-import 'package:analyzer/src/dart/element/type_system.dart';
-import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/error/return_type_verifier.dart';
-import 'package:analyzer/src/generated/error_verifier.dart';
-
-/// Reports on invalid functions passed to [Future.catchError].
-class CatchErrorVerifier {
-  final ErrorReporter _errorReporter;
-
-  final TypeProviderImpl _typeProvider;
-
-  final TypeSystemImpl _typeSystem;
-
-  final ReturnTypeVerifier _returnTypeVerifier;
-
-  CatchErrorVerifier(this._errorReporter, this._typeProvider, this._typeSystem)
-      : _returnTypeVerifier = ReturnTypeVerifier(
-          typeProvider: _typeProvider,
-          typeSystem: _typeSystem,
-          errorReporter: _errorReporter,
-        );
-
-  void verifyMethodInvocation(MethodInvocation node) {
-    var target = node.realTarget;
-    if (target == null) {
-      return;
-    }
-    var methodName = node.methodName;
-    if (!(methodName.name == 'catchError' &&
-        target.typeOrThrow.isDartAsyncFuture)) {
-      return;
-    }
-    if (node.argumentList.arguments.isEmpty) {
-      return;
-    }
-    var callback = node.argumentList.arguments.first;
-    if (callback is NamedExpression) {
-      // This implies that no positional arguments are passed.
-      return;
-    }
-    var targetType = target.staticType as InterfaceType;
-    var targetFutureType = targetType.typeArguments.first;
-    var expectedReturnType = _typeProvider.futureOrType(targetFutureType);
-    if (callback is FunctionExpression) {
-      // TODO(migration): should be FunctionType, not nullable
-      var callbackType = callback.staticType as FunctionType;
-      _checkOnErrorFunctionType(callback, callbackType, expectedReturnType);
-      var catchErrorOnErrorExecutable = EnclosingExecutableContext(
-          callback.declaredElement,
-          isAsynchronous: true,
-          catchErrorOnErrorReturnType: expectedReturnType);
-      var returnStatementVerifier =
-          _ReturnStatementVerifier(_returnTypeVerifier);
-      _returnTypeVerifier.enclosingExecutable = catchErrorOnErrorExecutable;
-      callback.body.accept(returnStatementVerifier);
-    } else {
-      var callbackType = callback.staticType;
-      if (callbackType is FunctionType) {
-        _checkReturnType(expectedReturnType, callbackType.returnType, callback);
-        _checkOnErrorFunctionType(callback, callbackType, expectedReturnType);
-      } else {
-        // If [callback] is not even a Function, then ErrorVerifier will have
-        // reported this.
-      }
-    }
-  }
-
-  void _checkOnErrorFunctionType(Expression expression,
-      FunctionType expressionType, DartType expectedFunctionReturnType) {
-    void report() {
-      _errorReporter.reportErrorForNode(
-        HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR,
-        expression,
-        [expressionType, expectedFunctionReturnType],
-      );
-    }
-
-    var parameters = expressionType.parameters;
-    if (parameters.isEmpty) {
-      return report();
-    }
-    var firstParameter = parameters.first;
-    if (firstParameter.isNamed) {
-      return report();
-    } else {
-      if (!_typeSystem.isSubtypeOf(
-          _typeProvider.objectType, firstParameter.type)) {
-        return report();
-      }
-    }
-    if (parameters.length == 2) {
-      var secondParameter = parameters[1];
-      if (secondParameter.isNamed) {
-        return report();
-      } else {
-        if (!_typeSystem.isSubtypeOf(
-            _typeProvider.stackTraceType, secondParameter.type)) {
-          return report();
-        }
-      }
-    } else if (parameters.length > 2) {
-      return report();
-    }
-  }
-
-  void _checkReturnType(
-      DartType expectedType, DartType functionReturnType, Expression callback) {
-    if (!_typeSystem.isAssignableTo(functionReturnType, expectedType)) {
-      _errorReporter.reportErrorForNode(
-        HintCode.RETURN_TYPE_INVALID_FOR_CATCH_ERROR,
-        callback,
-        [functionReturnType, expectedType],
-      );
-    }
-  }
-}
-
-/// Visits a function body, looking for return statements.
-class _ReturnStatementVerifier extends RecursiveAstVisitor<void> {
-  final ReturnTypeVerifier _returnTypeVerifier;
-
-  _ReturnStatementVerifier(this._returnTypeVerifier);
-
-  @override
-  void visitExpressionFunctionBody(ExpressionFunctionBody node) {
-    _returnTypeVerifier.verifyExpressionFunctionBody(node);
-    super.visitExpressionFunctionBody(node);
-  }
-
-  @override
-  void visitFunctionExpression(FunctionExpression node) {
-    // Do not visit within [node]. We have no interest in return statements
-    // within.
-  }
-  @override
-  void visitReturnStatement(ReturnStatement node) {
-    _returnTypeVerifier.verifyReturnStatement(node);
-    super.visitReturnStatement(node);
-  }
-}
diff --git a/pkg/analyzer/lib/src/error/error_handler_verifier.dart b/pkg/analyzer/lib/src/error/error_handler_verifier.dart
new file mode 100644
index 0000000..0706474
--- /dev/null
+++ b/pkg/analyzer/lib/src/error/error_handler_verifier.dart
@@ -0,0 +1,281 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
+import 'package:analyzer/src/dart/element/type_system.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/error/return_type_verifier.dart';
+import 'package:analyzer/src/generated/error_verifier.dart';
+import 'package:collection/collection.dart';
+
+/// Reports on invalid functions passed as error handlers.
+///
+/// Functions must either accept exactly one positional parameter, or exactly
+/// two positional parameters. The one parameter (or the first parameter) must
+/// have a type of `dynamic`, `Object`, or `Object?`. If a second parameter is
+/// accepted, it must have a type of `StackTrace`.
+///
+/// A function is checked if it is passed as:
+/// * as the first argument to [Future.catchError],
+/// * as the 'onError' named argument to [Future.then],
+/// * as the first argument to [Stream.handleError],
+/// * as the 'onError' named argument to [Future.onError],
+/// * as the first argument to [StreamSubscription.onError],
+///
+/// Additionally, a function passed as the first argument to
+/// [Future<T>.catchError] must return `FutureOr<T>`, and any return statements in a
+/// function literal must return a value of type `FutureOr<T>`.
+class ErrorHandlerVerifier {
+  final ErrorReporter _errorReporter;
+
+  final TypeProviderImpl _typeProvider;
+
+  final TypeSystemImpl _typeSystem;
+
+  final ReturnTypeVerifier _returnTypeVerifier;
+
+  ErrorHandlerVerifier(
+      this._errorReporter, this._typeProvider, this._typeSystem)
+      : _returnTypeVerifier = ReturnTypeVerifier(
+          typeProvider: _typeProvider,
+          typeSystem: _typeSystem,
+          errorReporter: _errorReporter,
+        );
+
+  void verifyMethodInvocation(MethodInvocation node) {
+    var target = node.realTarget;
+    if (target == null) {
+      return;
+    }
+
+    if (node.argumentList.arguments.isEmpty) {
+      return;
+    }
+
+    var targetType = target.staticType;
+    if (targetType == null) {
+      return;
+    }
+    var methodName = node.methodName.name;
+    if (methodName == 'catchError' && targetType.isDartAsyncFuture) {
+      var callback = node.argumentList.arguments.first;
+      if (callback is NamedExpression) {
+        // This implies that no positional arguments are passed.
+        return;
+      }
+      _checkFutureCatchErrorOnError(target, callback);
+      return;
+    }
+
+    if (methodName == 'then' && targetType.isDartAsyncFuture) {
+      var callback = node.argumentList.arguments
+          .whereType<NamedExpression>()
+          .firstWhereOrNull(
+              (argument) => argument.name.label.name == 'onError');
+      if (callback == null) {
+        return;
+      }
+      var callbackType = callback.staticType;
+      if (callbackType == null) {
+        return;
+      }
+      if (callbackType is FunctionType) {
+        // TODO(srawlins): Also check return type of the 'onError' named
+        // argument to [Future<T>.then].
+        _checkErrorHandlerFunctionType(
+            callback, callbackType, _typeProvider.voidType,
+            checkFirstParameterType: callback.expression is FunctionExpression);
+        return;
+      }
+      // [callbackType] might be dart:core's Function, or something not
+      // assignable to Function, in which case an error is reported elsewhere.
+    }
+
+    if (methodName == 'handleError' &&
+        _isDartCoreAsyncType(targetType, 'Stream')) {
+      var callback = node.argumentList.arguments.first;
+      if (callback is NamedExpression) {
+        // This implies that no positional arguments are passed.
+        return;
+      }
+      var callbackType = callback.staticType;
+      if (callbackType == null) {
+        return;
+      }
+      if (callbackType is FunctionType) {
+        _checkErrorHandlerFunctionType(
+            callback, callbackType, _typeProvider.voidType,
+            checkFirstParameterType: callback is FunctionExpression);
+        return;
+      }
+      // [callbackType] might be dart:core's Function, or something not
+      // assignable to Function, in which case an error is reported elsewhere.
+    }
+
+    if (methodName == 'listen' && _isDartCoreAsyncType(targetType, 'Stream')) {
+      var callback = node.argumentList.arguments
+          .whereType<NamedExpression>()
+          .firstWhereOrNull(
+              (argument) => argument.name.label.name == 'onError');
+      if (callback == null) {
+        return;
+      }
+      var callbackType = callback.staticType;
+      if (callbackType == null) {
+        return;
+      }
+      if (callbackType is FunctionType) {
+        _checkErrorHandlerFunctionType(
+            callback, callbackType, _typeProvider.voidType,
+            checkFirstParameterType: callback.expression is FunctionExpression);
+        return;
+      }
+      // [callbackType] might be dart:core's Function, or something not
+      // assignable to Function, in which case an error is reported elsewhere.
+    }
+
+    if (methodName == 'onError' &&
+        _isDartCoreAsyncType(targetType, 'StreamSubscription')) {
+      var callback = node.argumentList.arguments.first;
+      if (callback is NamedExpression) {
+        // This implies that no positional arguments are passed.
+        return;
+      }
+      var callbackType = callback.staticType;
+      if (callbackType == null) {
+        return;
+      }
+      if (callbackType is FunctionType) {
+        _checkErrorHandlerFunctionType(
+            callback, callbackType, _typeProvider.voidType,
+            checkFirstParameterType: callback is FunctionExpression);
+        return;
+      }
+      // [callbackType] might be dart:core's Function, or something not
+      // assignable to Function, in which case an error is reported elsewhere.
+    }
+  }
+
+  /// Checks that [expression], a function with static type [expressionType], is
+  /// a valid error handler.
+  ///
+  /// Only checks the first parameter type if [checkFirstParameterType] is true.
+  /// Certain error handlers are allowed to specify a different type for their
+  /// first parameter.
+  void _checkErrorHandlerFunctionType(Expression expression,
+      FunctionType expressionType, DartType expectedFunctionReturnType,
+      {bool checkFirstParameterType = true}) {
+    void report() {
+      _errorReporter.reportErrorForNode(
+        HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER,
+        expression,
+        [expressionType, expectedFunctionReturnType],
+      );
+    }
+
+    var parameters = expressionType.parameters;
+    if (parameters.isEmpty) {
+      return report();
+    }
+    var firstParameter = parameters.first;
+    if (firstParameter.isNamed) {
+      return report();
+    } else if (checkFirstParameterType) {
+      if (!_typeSystem.isSubtypeOf(
+          _typeProvider.objectType, firstParameter.type)) {
+        return report();
+      }
+    }
+    if (parameters.length == 2) {
+      var secondParameter = parameters[1];
+      if (secondParameter.isNamed) {
+        return report();
+      } else {
+        if (!_typeSystem.isSubtypeOf(
+            _typeProvider.stackTraceType, secondParameter.type)) {
+          return report();
+        }
+      }
+    } else if (parameters.length > 2) {
+      return report();
+    }
+  }
+
+  /// Check the 'onError' argument given to [Future.catchError].
+  void _checkFutureCatchErrorOnError(Expression target, Expression callback) {
+    var targetType = target.staticType as InterfaceType;
+    var targetFutureType = targetType.typeArguments.first;
+    var expectedReturnType = _typeProvider.futureOrType(targetFutureType);
+    if (callback is FunctionExpression) {
+      // TODO(migration): should be FunctionType, not nullable
+      var callbackType = callback.staticType as FunctionType;
+      _checkErrorHandlerFunctionType(
+          callback, callbackType, expectedReturnType);
+      var catchErrorOnErrorExecutable = EnclosingExecutableContext(
+          callback.declaredElement,
+          isAsynchronous: true,
+          catchErrorOnErrorReturnType: expectedReturnType);
+      var returnStatementVerifier =
+          _ReturnStatementVerifier(_returnTypeVerifier);
+      _returnTypeVerifier.enclosingExecutable = catchErrorOnErrorExecutable;
+      callback.body.accept(returnStatementVerifier);
+    } else {
+      var callbackType = callback.staticType;
+      if (callbackType is FunctionType) {
+        _checkReturnType(expectedReturnType, callbackType.returnType, callback);
+        _checkErrorHandlerFunctionType(
+            callback, callbackType, expectedReturnType);
+      } else {
+        // If [callback] is not even a Function, then ErrorVerifier will have
+        // reported this.
+      }
+    }
+  }
+
+  void _checkReturnType(
+      DartType expectedType, DartType functionReturnType, Expression callback) {
+    if (!_typeSystem.isAssignableTo(functionReturnType, expectedType)) {
+      _errorReporter.reportErrorForNode(
+        HintCode.RETURN_TYPE_INVALID_FOR_CATCH_ERROR,
+        callback,
+        [functionReturnType, expectedType],
+      );
+    }
+  }
+
+  /// Returns whether [element] represents the []
+  bool _isDartCoreAsyncType(DartType type, String typeName) =>
+      type is InterfaceType &&
+      type.element.name == typeName &&
+      type.element.library.isDartAsync;
+}
+
+/// Visits a function body, looking for return statements.
+class _ReturnStatementVerifier extends RecursiveAstVisitor<void> {
+  final ReturnTypeVerifier _returnTypeVerifier;
+
+  _ReturnStatementVerifier(this._returnTypeVerifier);
+
+  @override
+  void visitExpressionFunctionBody(ExpressionFunctionBody node) {
+    _returnTypeVerifier.verifyExpressionFunctionBody(node);
+    super.visitExpressionFunctionBody(node);
+  }
+
+  @override
+  void visitFunctionExpression(FunctionExpression node) {
+    // Do not visit within [node]. We have no interest in return statements
+    // within.
+  }
+
+  @override
+  void visitReturnStatement(ReturnStatement node) {
+    _returnTypeVerifier.verifyReturnStatement(node);
+    super.visitReturnStatement(node);
+  }
+}
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index 74bcc94..e588646 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -44,7 +44,7 @@
 
   Future<T> catchError(Function onError, {bool test(Object error)});
 
-  Future<R> then<R>(FutureOr<R> onValue(T value));
+  Future<R> then<R>(FutureOr<R> onValue(T value), {Function? onError});
 
   Future<T> whenComplete(action());
 
@@ -90,6 +90,8 @@
 
   StreamSubscription<T> listen(void onData(T event)?,
       {Function? onError, void onDone()?, bool? cancelOnError});
+
+  Stream<T> handleError(Function onError, {bool test(dynamic error)});
 }
 
 abstract class StreamIterator<T> {}
diff --git a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_catch_error_on_error_test.dart b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_catch_error_on_error_test.dart
deleted file mode 100644
index ceb0706..0000000
--- a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_catch_error_on_error_test.dart
+++ /dev/null
@@ -1,277 +0,0 @@
-// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/src/error/codes.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import '../dart/resolution/context_collection_resolution.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(ArgumentTypeNotAssignableCatchErrorOnErrorTest);
-    defineReflectiveTests(
-        ArgumentTypeNotAssignableCatchErrorOnErrorWithNullSafetyTest);
-  });
-}
-
-@reflectiveTest
-class ArgumentTypeNotAssignableCatchErrorOnErrorTest
-    extends PubPackageResolutionTest with WithoutNullSafetyMixin {
-  void test_firstParameterIsDynamic() async {
-    await assertNoErrorsInCode('''
-void f(Future<int> future, Future<int> Function(dynamic a) callback) {
-  future.catchError(callback);
-}
-''');
-  }
-
-  void test_firstParameterIsNamed() async {
-    await assertErrorsInCode('''
-void f(Future<int> future, Future<int> Function({Object a}) callback) {
-  future.catchError(callback);
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 92, 8),
-    ]);
-  }
-
-  void test_firstParameterIsOptional() async {
-    await assertNoErrorsInCode('''
-void f(Future<int> future, Future<int> Function([Object a]) callback) {
-  future.catchError(callback);
-}
-''');
-  }
-
-  void test_functionExpression_firstParameterIsDynamic() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((dynamic a) {});
-}
-''');
-  }
-
-  void test_functionExpression_firstParameterIsImplicit() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((a) {});
-}
-''');
-  }
-
-  void test_functionExpression_firstParameterIsNamed() async {
-    await assertErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError(({Object a = 1}) {});
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 50, 19),
-    ]);
-  }
-
-  void test_functionExpression_firstParameterIsOptional() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError(([Object a = 1]) {});
-}
-''');
-  }
-
-  void test_functionExpression_firstParameterIsVar() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((var a) {});
-}
-''');
-  }
-
-  void test_functionExpression_noParameters() async {
-    await assertErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError(() {});
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 50, 5),
-    ]);
-  }
-
-  void test_functionExpression_secondParameterIsDynamic() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((Object a, dynamic b) {});
-}
-''');
-  }
-
-  void test_functionExpression_secondParameterIsImplicit() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((Object a, b) {});
-}
-''');
-  }
-
-  void test_functionExpression_secondParameterIsNamed() async {
-    await assertErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((Object a, {StackTrace b}) {});
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 50, 29),
-    ]);
-  }
-
-  void test_functionExpression_secondParameterIsOptional() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((Object a, [StackTrace st]) {});
-}
-''');
-  }
-
-  void test_functionExpression_secondParameterIsVar() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((Object a, var b) {});
-}
-''');
-  }
-
-  void test_functionExpression_tooManyParameters() async {
-    await assertErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((a, b, c) {});
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 50, 12),
-    ]);
-  }
-
-  void test_functionExpression_wrongFirstParameterType() async {
-    await assertErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((String a) {});
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 50, 13),
-    ]);
-  }
-
-  void test_functionExpression_wrongSecondParameterType() async {
-    await assertErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((Object a, String b) {});
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 50, 23),
-    ]);
-  }
-
-  void test_noParameters() async {
-    await assertErrorsInCode('''
-void f(Future<int> future, Future<int> Function() callback) {
-  future.catchError(callback);
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 82, 8),
-    ]);
-  }
-
-  void test_okType() async {
-    await assertNoErrorsInCode('''
-void f(Future<int> future, Future<int> Function(Object, StackTrace) callback) {
-  future.catchError(callback);
-}
-''');
-  }
-
-  void test_secondParameterIsDynamic() async {
-    await assertNoErrorsInCode('''
-void f(Future<int> future, Future<int> Function(Object a, dynamic b) callback) {
-  future.catchError(callback);
-}
-''');
-  }
-
-  void test_secondParameterIsNamed() async {
-    await assertErrorsInCode('''
-void f(Future<int> future, Future<int> Function(Object a, {StackTrace b}) callback) {
-  future.catchError(callback);
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 106, 8),
-    ]);
-  }
-
-  void test_tooManyParameters() async {
-    await assertErrorsInCode('''
-void f(Future<int> future, Future<int> Function(int, int, int) callback) {
-  future.catchError(callback);
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 95, 8),
-    ]);
-  }
-
-  void test_wrongSecondParameterType() async {
-    await assertErrorsInCode('''
-void f(Future<int> future, Future<int> Function(Object, String) callback) {
-  future.catchError(callback);
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 96, 8),
-    ]);
-  }
-
-  voidtest_wrongFirstParameterType() async {
-    await assertErrorsInCode('''
-void f(Future<int> future, Future<int> Function(String) callback) {
-  future.catchError(callback);
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 88, 8),
-    ]);
-  }
-}
-
-@reflectiveTest
-class ArgumentTypeNotAssignableCatchErrorOnErrorWithNullSafetyTest
-    extends ArgumentTypeNotAssignableCatchErrorOnErrorTest
-    with WithNullSafetyMixin {
-  void test_functionExpression_firstParameterIsNullableObject() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((Object? a) {});
-}
-''');
-  }
-
-  @override
-  void test_functionExpression_secondParameterIsNamed() async {
-    await assertErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((Object a, {required StackTrace b}) {});
-}
-''', [
-      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_CATCH_ERROR_ON_ERROR, 50, 38),
-    ]);
-  }
-
-  void test_functionExpression_secondParameterIsNullableStackTrace() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((Object a, StackTrace? b) {});
-}
-''');
-  }
-
-  @override
-  void test_functionExpression_secondParameterIsOptional() async {
-    await assertNoErrorsInCode('''
-void f(Future<void> future) {
-  future.catchError((Object a, [StackTrace? st]) {});
-}
-''');
-  }
-}
diff --git a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_to_error_handler_test.dart b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_to_error_handler_test.dart
new file mode 100644
index 0000000..eaeddb5
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_to_error_handler_test.dart
@@ -0,0 +1,704 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(
+        ArgumentTypeNotAssignableToErrorHandler_FutureCatchErrorTest);
+    defineReflectiveTests(
+        ArgumentTypeNotAssignableToErrorHandler_FutureCatchErrorWithoutNullSafetyTest);
+    defineReflectiveTests(
+        ArgumentTypeNotAssignableToErrorHandler_FutureThenTest);
+    defineReflectiveTests(
+        ArgumentTypeNotAssignableToErrorHandler_FutureThenWithoutNullSafetyTest);
+    defineReflectiveTests(
+        ArgumentTypeNotAssignableToErrorHandler_StreamHandleErrorTest);
+    defineReflectiveTests(
+        ArgumentTypeNotAssignableToErrorHandler_StreamHandleErrorWithoutNullSafetyTest);
+    defineReflectiveTests(
+        ArgumentTypeNotAssignableToErrorHandler_StreamListenTest);
+    defineReflectiveTests(
+        ArgumentTypeNotAssignableToErrorHandler_StreamListenWithoutNullSafetyTest);
+    defineReflectiveTests(
+        ArgumentTypeNotAssignableToErrorHandler_StreamSubscriptionOnErrorTest);
+    defineReflectiveTests(
+        ArgumentTypeNotAssignableToErrorHandler_StreamSubscriptionOnErrorWithoutNullSafetyTest);
+  });
+}
+
+@reflectiveTest
+class ArgumentTypeNotAssignableToErrorHandler_FutureCatchErrorTest
+    extends PubPackageResolutionTest
+    with ArgumentTypeNotAssignableToErrorHandler_FutureCatchErrorTestCases {
+  void test_functionExpression_firstParameterIsNullableObject() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((Object? a) {});
+}
+''');
+  }
+
+  @override
+  void test_functionExpression_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((Object a, {required StackTrace b}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 50, 38),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsNullableStackTrace() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((Object a, StackTrace? b) {});
+}
+''');
+  }
+}
+
+mixin ArgumentTypeNotAssignableToErrorHandler_FutureCatchErrorTestCases
+    on PubPackageResolutionTest {
+  void test_firstParameterIsDynamic() async {
+    await assertNoErrorsInCode('''
+void f(Future<int> future, Future<int> Function(dynamic a) callback) {
+  future.catchError(callback);
+}
+''');
+  }
+
+  void test_firstParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Future<int> future, Future<int> Function({Object a}) callback) {
+  future.catchError(callback);
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 92, 8),
+    ]);
+  }
+
+  void test_firstParameterIsOptional() async {
+    await assertNoErrorsInCode('''
+void f(Future<int> future, Future<int> Function([Object a]) callback) {
+  future.catchError(callback);
+}
+''');
+  }
+
+  void test_functionExpression_firstParameterIsDynamic() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((dynamic a) {});
+}
+''');
+  }
+
+  void test_functionExpression_firstParameterIsImplicit() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((a) {});
+}
+''');
+  }
+
+  void test_functionExpression_firstParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError(({Object a = 1}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 50, 19),
+    ]);
+  }
+
+  void test_functionExpression_firstParameterIsOptional() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError(([Object a = 1]) {});
+}
+''');
+  }
+
+  void test_functionExpression_firstParameterIsVar() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((var a) {});
+}
+''');
+  }
+
+  void test_functionExpression_noParameters() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError(() {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 50, 5),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsDynamic() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((Object a, dynamic b) {});
+}
+''');
+  }
+
+  void test_functionExpression_secondParameterIsImplicit() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((Object a, b) {});
+}
+''');
+  }
+
+  void test_functionExpression_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((Object a, {StackTrace b}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 50, 29),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsVar() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((Object a, var b) {});
+}
+''');
+  }
+
+  void test_functionExpression_tooManyParameters() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((a, b, c) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 50, 12),
+    ]);
+  }
+
+  void test_functionExpression_wrongFirstParameterType() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((String a) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 50, 13),
+    ]);
+  }
+
+  void test_functionExpression_wrongSecondParameterType() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.catchError((Object a, String b) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 50, 23),
+    ]);
+  }
+
+  void test_noParameters() async {
+    await assertErrorsInCode('''
+void f(Future<int> future, Future<int> Function() callback) {
+  future.catchError(callback);
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 82, 8),
+    ]);
+  }
+
+  void test_okType() async {
+    await assertNoErrorsInCode('''
+void f(Future<int> future, Future<int> Function(Object, StackTrace) callback) {
+  future.catchError(callback);
+}
+''');
+  }
+
+  void test_secondParameterIsDynamic() async {
+    await assertNoErrorsInCode('''
+void f(Future<int> future, Future<int> Function(Object a, dynamic b) callback) {
+  future.catchError(callback);
+}
+''');
+  }
+
+  void test_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Future<int> future, Future<int> Function(Object a, {StackTrace b}) callback) {
+  future.catchError(callback);
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 106, 8),
+    ]);
+  }
+
+  void test_tooManyParameters() async {
+    await assertErrorsInCode('''
+void f(Future<int> future, Future<int> Function(int, int, int) callback) {
+  future.catchError(callback);
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 95, 8),
+    ]);
+  }
+
+  void test_wrongFirstParameterType() async {
+    await assertErrorsInCode('''
+void f(Future<int> future, Future<int> Function(String) callback) {
+  future.catchError(callback);
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 88, 8),
+    ]);
+  }
+
+  void test_wrongSecondParameterType() async {
+    await assertErrorsInCode('''
+void f(Future<int> future, Future<int> Function(Object, String) callback) {
+  future.catchError(callback);
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 96, 8),
+    ]);
+  }
+}
+
+@reflectiveTest
+class ArgumentTypeNotAssignableToErrorHandler_FutureCatchErrorWithoutNullSafetyTest
+    extends PubPackageResolutionTest
+    with
+        ArgumentTypeNotAssignableToErrorHandler_FutureCatchErrorTestCases,
+        WithoutNullSafetyMixin {}
+
+@reflectiveTest
+class ArgumentTypeNotAssignableToErrorHandler_FutureThenTest
+    extends PubPackageResolutionTest
+    with ArgumentTypeNotAssignableToErrorHandler_FutureThenTestCases {
+  void test_functionExpression_firstParameterIsNullableObject() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.then((_) {}, onError: (Object? a) {});
+}
+''');
+  }
+
+  @override
+  void test_functionExpression_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.then((_) {}, onError: (Object a, {StackTrace? b}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 52, 39),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsNullableStackTrace() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future) {
+  future.then((_) {}, onError: (Object a, StackTrace? b) {});
+}
+''');
+  }
+}
+
+mixin ArgumentTypeNotAssignableToErrorHandler_FutureThenTestCases
+    on PubPackageResolutionTest {
+  void test_firstParameterIsDynamic() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future, void Function(dynamic a) callback) {
+  future.then((_) {}, onError: callback);
+}
+''');
+  }
+
+  void test_firstParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Future<void> future, Future<int> Function({Object a}) callback) {
+  future.then((_) {}, onError: callback);
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 95, 17),
+    ]);
+  }
+
+  void test_functionExpression_firstParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.then((_) {}, onError: ({Object a = 1}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 52, 28),
+    ]);
+  }
+
+  void test_functionExpression_noParameters() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.then((_) {}, onError: () {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 52, 14),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.then((_) {}, onError: (Object a, {StackTrace b}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 52, 38),
+    ]);
+  }
+
+  void test_functionExpression_wrongFirstParameterType() async {
+    await assertErrorsInCode('''
+void f(Future<void> future) {
+  future.then((_) {}, onError: (String a) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 52, 22),
+    ]);
+  }
+
+  void test_functionType() async {
+    await assertNoErrorsInCode('''
+void f(Future<void> future, Function callback) {
+  future.then((_) {}, onError: callback);
+}
+''');
+  }
+}
+
+@reflectiveTest
+class ArgumentTypeNotAssignableToErrorHandler_FutureThenWithoutNullSafetyTest
+    extends PubPackageResolutionTest
+    with
+        ArgumentTypeNotAssignableToErrorHandler_FutureThenTestCases,
+        WithoutNullSafetyMixin {}
+
+@reflectiveTest
+class ArgumentTypeNotAssignableToErrorHandler_StreamHandleErrorTest
+    extends PubPackageResolutionTest
+    with ArgumentTypeNotAssignableToErrorHandler_StreamHandleErrorTestCases {
+  void test_functionExpression_firstParameterIsNullableObject() async {
+    await assertNoErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.handleError((Object? a) {});
+}
+''');
+  }
+
+  @override
+  void test_functionExpression_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.handleError((Object a, {StackTrace? b}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 51, 30),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsNullableStackTrace() async {
+    await assertNoErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.handleError((Object a, StackTrace? b) {});
+}
+''');
+  }
+}
+
+mixin ArgumentTypeNotAssignableToErrorHandler_StreamHandleErrorTestCases
+    on PubPackageResolutionTest {
+  void test_firstParameterIsDynamic() async {
+    await assertNoErrorsInCode('''
+void f(Stream<void> stream, void Function(dynamic a) callback) {
+  stream.handleError(callback);
+}
+''');
+  }
+
+  void test_firstParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream, Future<int> Function({Object a}) callback) {
+  stream.handleError(callback);
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 94, 8),
+    ]);
+  }
+
+  void test_functionExpression_firstParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.handleError(({Object a = 1}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 51, 19),
+    ]);
+  }
+
+  void test_functionExpression_noParameters() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.handleError(() {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 51, 5),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.handleError((Object a, {StackTrace b}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 51, 29),
+    ]);
+  }
+
+  void test_functionExpression_wrongFirstParameterType() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.handleError((String a) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 51, 13),
+    ]);
+  }
+}
+
+@reflectiveTest
+class ArgumentTypeNotAssignableToErrorHandler_StreamHandleErrorWithoutNullSafetyTest
+    extends PubPackageResolutionTest
+    with
+        ArgumentTypeNotAssignableToErrorHandler_StreamHandleErrorTestCases,
+        WithoutNullSafetyMixin {}
+
+@reflectiveTest
+class ArgumentTypeNotAssignableToErrorHandler_StreamListenTest
+    extends PubPackageResolutionTest
+    with ArgumentTypeNotAssignableToErrorHandler_StreamListenTestCases {
+  void test_functionExpression_firstParameterIsNullableObject() async {
+    await assertNoErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.listen((_) {}, onError: (Object? a) {});
+}
+''');
+  }
+
+  @override
+  void test_functionExpression_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.listen((_) {}, onError: (Object a, {StackTrace? b}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 54, 39),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsNullableStackTrace() async {
+    await assertNoErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.listen((_) {}, onError: (Object a, StackTrace? b) {});
+}
+''');
+  }
+}
+
+mixin ArgumentTypeNotAssignableToErrorHandler_StreamListenTestCases
+    on PubPackageResolutionTest {
+  void test_firstParameterIsDynamic() async {
+    await assertNoErrorsInCode('''
+void f(Stream<void> stream, void Function(dynamic a) callback) {
+  stream.listen((_) {}, onError: callback);
+}
+''');
+  }
+
+  void test_firstParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream, Future<int> Function({Object a}) callback) {
+  stream.listen((_) {}, onError: callback);
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 97, 17),
+    ]);
+  }
+
+  void test_functionExpression_firstParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.listen((_) {}, onError: ({Object a = 1}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 54, 28),
+    ]);
+  }
+
+  void test_functionExpression_noParameters() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.listen((_) {}, onError: () {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 54, 14),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.listen((_) {}, onError: (Object a, {StackTrace b}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 54, 38),
+    ]);
+  }
+
+  void test_functionExpression_wrongFirstParameterType() async {
+    await assertErrorsInCode('''
+void f(Stream<void> stream) {
+  stream.listen((_) {}, onError: (String a) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 54, 22),
+    ]);
+  }
+}
+
+@reflectiveTest
+class ArgumentTypeNotAssignableToErrorHandler_StreamListenWithoutNullSafetyTest
+    extends PubPackageResolutionTest
+    with
+        ArgumentTypeNotAssignableToErrorHandler_StreamListenTestCases,
+        WithoutNullSafetyMixin {}
+
+@reflectiveTest
+class ArgumentTypeNotAssignableToErrorHandler_StreamSubscriptionOnErrorTest
+    extends PubPackageResolutionTest
+    with
+        ArgumentTypeNotAssignableToErrorHandler_StreamSubscriptionOnErrorTestCases {
+  void test_functionExpression_firstParameterIsNullableObject() async {
+    await assertNoErrorsInCode('''
+import 'dart:async';
+void f(StreamSubscription<void> subscription) {
+  subscription.onError((Object? a) {});
+}
+''');
+  }
+
+  @override
+  void test_functionExpression_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+import 'dart:async';
+void f(StreamSubscription<void> subscription) {
+  subscription.onError((Object a, {StackTrace? b}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 92, 30),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsNullableStackTrace() async {
+    await assertNoErrorsInCode('''
+import 'dart:async';
+void f(StreamSubscription<void> subscription) {
+  subscription.onError((Object a, StackTrace? b) {});
+}
+''');
+  }
+}
+
+mixin ArgumentTypeNotAssignableToErrorHandler_StreamSubscriptionOnErrorTestCases
+    on PubPackageResolutionTest {
+  void test_firstParameterIsDynamic() async {
+    await assertNoErrorsInCode('''
+import 'dart:async';
+void f(
+    StreamSubscription<void> subscription, void Function(dynamic a) callback) {
+  subscription.onError(callback);
+}
+''');
+  }
+
+  void test_firstParameterIsNamed() async {
+    await assertErrorsInCode('''
+import 'dart:async';
+void f(
+    StreamSubscription<void> subscription,
+    Future<int> Function({Object a}) callback) {
+  subscription.onError(callback);
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 144, 8),
+    ]);
+  }
+
+  void test_functionExpression_firstParameterIsNamed() async {
+    await assertErrorsInCode('''
+import 'dart:async';
+void f(StreamSubscription<void> subscription) {
+  subscription.onError(({Object a = 1}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 92, 19),
+    ]);
+  }
+
+  void test_functionExpression_noParameters() async {
+    await assertErrorsInCode('''
+import 'dart:async';
+void f(StreamSubscription<void> subscription) {
+  subscription.onError(() {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 92, 5),
+    ]);
+  }
+
+  void test_functionExpression_secondParameterIsNamed() async {
+    await assertErrorsInCode('''
+import 'dart:async';
+void f(StreamSubscription<void> subscription) {
+  subscription.onError((Object a, {StackTrace b}) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 92, 29),
+    ]);
+  }
+
+  void test_functionExpression_wrongFirstParameterType() async {
+    await assertErrorsInCode('''
+import 'dart:async';
+void f(StreamSubscription<void> subscription) {
+  subscription.onError((String a) {});
+}
+''', [
+      error(HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER, 92, 13),
+    ]);
+  }
+}
+
+@reflectiveTest
+class ArgumentTypeNotAssignableToErrorHandler_StreamSubscriptionOnErrorWithoutNullSafetyTest
+    extends PubPackageResolutionTest
+    with
+        ArgumentTypeNotAssignableToErrorHandler_StreamSubscriptionOnErrorTestCases,
+        WithoutNullSafetyMixin {}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 8b1a3b1..11cd8e8 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -17,9 +17,9 @@
 import 'ambiguous_set_or_map_literal_test.dart' as ambiguous_set_or_map_literal;
 import 'annotation_on_pointer_field_test.dart' as annotation_on_pointer_field;
 import 'annotation_syntax_test.dart' as annotation_syntax;
-import 'argument_type_not_assignable_catch_error_on_error_test.dart'
-    as argument_type_not_assignable_catch_error_on_error;
 import 'argument_type_not_assignable_test.dart' as argument_type_not_assignable;
+import 'argument_type_not_assignable_to_error_handler_test.dart'
+    as argument_type_not_assignable_to_error_handler;
 import 'assert_in_redirecting_constructor_test.dart'
     as assert_in_redirecting_constructor;
 import 'assignment_of_do_not_store_test.dart' as assignment_of_do_not_store;
@@ -683,7 +683,7 @@
     annotation_on_pointer_field.main();
     annotation_syntax.main();
     argument_type_not_assignable.main();
-    argument_type_not_assignable_catch_error_on_error.main();
+    argument_type_not_assignable_to_error_handler.main();
     assert_in_redirecting_constructor.main();
     assignment_of_do_not_store.main();
     assignment_to_const.main();
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 1bbce68..db471a1 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -3316,16 +3316,13 @@
     //
     // In the body of an `async`, `await` is generated simply as `yield`.
     var gen = emitGeneratorFn((_) => []);
-    // Return type of an async body is `Future<flatten(T)>`, where T is the
-    // declared return type, unless T is Object. In that case the Object refers
-    // to a return type of `Future<Object?>`.
-    // TODO(nshahan) Use the Future type value when available on a FunctionNode.
-    var declaredReturnType = function
-        .computeThisFunctionType(_currentLibrary.nonNullable)
-        .returnType;
-    var returnType = _coreTypes.isObject(declaredReturnType)
-        ? _coreTypes.objectNullableRawType
-        : _types.flatten(declaredReturnType);
+    var returnType = _currentLibrary.isNonNullableByDefault
+        ? function.futureValueType
+        // Otherwise flatten the return type because futureValueType(T) is not
+        // defined for legacy libraries.
+        : _types.flatten(function
+            .computeThisFunctionType(_currentLibrary.nonNullable)
+            .returnType);
     return js.call('#.async(#, #)',
         [emitLibraryName(_coreTypes.asyncLibrary), _emitType(returnType), gen]);
   }
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
index 1915787..699e59c 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
@@ -16,6 +16,7 @@
   constantUpdate2018,
   controlFlowCollections,
   extensionMethods,
+  extensionTypes,
   genericMetadata,
   nonNullable,
   nonfunctionTypeAliases,
@@ -31,6 +32,7 @@
 const Version enableConstantUpdate2018Version = const Version(2, 0);
 const Version enableControlFlowCollectionsVersion = const Version(2, 0);
 const Version enableExtensionMethodsVersion = const Version(2, 6);
+const Version enableExtensionTypesVersion = const Version(2, 13);
 const Version enableGenericMetadataVersion = const Version(2, 13);
 const Version enableNonNullableVersion = const Version(2, 12);
 const Version enableNonfunctionTypeAliasesVersion = const Version(2, 13);
@@ -50,6 +52,8 @@
       return ExperimentalFlag.controlFlowCollections;
     case "extension-methods":
       return ExperimentalFlag.extensionMethods;
+    case "extension-types":
+      return ExperimentalFlag.extensionTypes;
     case "generic-metadata":
       return ExperimentalFlag.genericMetadata;
     case "non-nullable":
@@ -75,6 +79,7 @@
   ExperimentalFlag.constantUpdate2018: true,
   ExperimentalFlag.controlFlowCollections: true,
   ExperimentalFlag.extensionMethods: true,
+  ExperimentalFlag.extensionTypes: true,
   ExperimentalFlag.genericMetadata: false,
   ExperimentalFlag.nonNullable: true,
   ExperimentalFlag.nonfunctionTypeAliases: false,
@@ -90,6 +95,7 @@
   ExperimentalFlag.constantUpdate2018: true,
   ExperimentalFlag.controlFlowCollections: true,
   ExperimentalFlag.extensionMethods: false,
+  ExperimentalFlag.extensionTypes: false,
   ExperimentalFlag.genericMetadata: false,
   ExperimentalFlag.nonNullable: false,
   ExperimentalFlag.nonfunctionTypeAliases: false,
@@ -105,6 +111,7 @@
   ExperimentalFlag.constantUpdate2018: const Version(2, 0),
   ExperimentalFlag.controlFlowCollections: const Version(2, 0),
   ExperimentalFlag.extensionMethods: const Version(2, 6),
+  ExperimentalFlag.extensionTypes: const Version(2, 13),
   ExperimentalFlag.genericMetadata: const Version(2, 13),
   ExperimentalFlag.nonNullable: const Version(2, 12),
   ExperimentalFlag.nonfunctionTypeAliases: const Version(2, 13),
@@ -120,6 +127,7 @@
   ExperimentalFlag.constantUpdate2018: const Version(2, 0),
   ExperimentalFlag.controlFlowCollections: const Version(2, 0),
   ExperimentalFlag.extensionMethods: const Version(2, 6),
+  ExperimentalFlag.extensionTypes: const Version(2, 13),
   ExperimentalFlag.genericMetadata: const Version(2, 13),
   ExperimentalFlag.nonNullable: const Version(2, 10),
   ExperimentalFlag.nonfunctionTypeAliases: const Version(2, 13),
diff --git a/runtime/vm/experimental_features.cc b/runtime/vm/experimental_features.cc
index fd0fe59..12b02ef 100644
--- a/runtime/vm/experimental_features.cc
+++ b/runtime/vm/experimental_features.cc
@@ -18,12 +18,7 @@
 
 bool GetExperimentalFeatureDefault(ExperimentalFeature feature) {
   constexpr bool kFeatureValues[] = {
-    true,
-    true,
-    true,
-    true,
-    true,
-    true,
+      true, true, true, true, true, true, true,
   };
   ASSERT(static_cast<size_t>(feature) < ARRAY_SIZE(kFeatureValues));
   return kFeatureValues[static_cast<int>(feature)];
@@ -31,12 +26,10 @@
 
 const char* GetExperimentalFeatureName(ExperimentalFeature feature) {
   constexpr const char* kFeatureNames[] = {
-    "non-nullable",
-    "extension-methods",
-    "constant-update-2018",
-    "control-flow-collections",
-    "set-literals",
-    "spread-collections",
+      "extension-types",          "non-nullable",
+      "extension-methods",        "constant-update-2018",
+      "control-flow-collections", "set-literals",
+      "spread-collections",
   };
   ASSERT(static_cast<size_t>(feature) < ARRAY_SIZE(kFeatureNames));
   return kFeatureNames[static_cast<int>(feature)];
diff --git a/runtime/vm/experimental_features.h b/runtime/vm/experimental_features.h
index 8efd29e..6418be6 100644
--- a/runtime/vm/experimental_features.h
+++ b/runtime/vm/experimental_features.h
@@ -14,6 +14,7 @@
 namespace dart {
 
 enum class ExperimentalFeature {
+  extension_types,
   non_nullable,
   extension_methods,
   constant_update_2018,
diff --git a/tools/VERSION b/tools/VERSION
index d35a7a6..88d050c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 45
+PRERELEASE 46
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/experimental_features.yaml b/tools/experimental_features.yaml
index bd85a2b..e97a0a3 100644
--- a/tools/experimental_features.yaml
+++ b/tools/experimental_features.yaml
@@ -124,6 +124,10 @@
 # on the command line, and will eventually be removed.
 #
 
+  extension-types:
+    help: "Extension Types"
+    enabledIn: '2.13.0'
+
   non-nullable:
     help: "Non Nullable by default"
     experimentalReleaseVersion: '2.10.0'