Migration: Properly handle `await`s of custom future classes.

Bug: https://b.corp.google.com/issues/200651131
Change-Id: Ia06066783a9107848f85bc234b7612a55f54c9c9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/214069
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 62cd9a3..078631a 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -489,9 +489,12 @@
   @override
   DecoratedType visitAwaitExpression(AwaitExpression node) {
     var expressionType = _dispatch(node.expression)!;
-    // TODO(paulberry) Handle subclasses of Future.
-    if (expressionType.type!.isDartAsyncFuture ||
-        expressionType.type!.isDartAsyncFutureOr) {
+    var type = expressionType.type!;
+    if (_typeSystem.isSubtypeOf(type, typeProvider.futureDynamicType)) {
+      expressionType = _decoratedClassHierarchy!
+          .asInstanceOf(expressionType, typeProvider.futureElement)
+          .typeArguments[0]!;
+    } else if (type.isDartAsyncFutureOr) {
       expressionType = expressionType.typeArguments[0]!;
     }
     return expressionType;
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 5307de5..9815198 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -1601,6 +1601,26 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  Future<void> test_custom_future() async {
+    var content = '''
+class CustomFuture<T> implements Future<T> {
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+f(CustomFuture<List<int>> x) async => (await x).first;
+''';
+    var expected = '''
+class CustomFuture<T> implements Future<T> {
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+f(CustomFuture<List<int>> x) async => (await x).first;
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   Future<void> test_data_flow_assignment_field() async {
     var content = '''
 class C {