[cfe] Eliminate UnknownType in async type downcasts

Cherry Pick CL for #42615

Closes https://github.com/dart-lang/sdk/issues/43013.

Bug: https://github.com/dart-lang/sdk/issues/42615
Change-Id: Ieb289acee04b3868304d320d3c2231fd6eb94dd6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/154322
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart b/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart
index 0251f0c..b56fc6b 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart
@@ -522,7 +522,8 @@
           statement.expression = inferrer.ensureAssignable(
               futureValueType, expressionType, statement.expression,
               fileOffset: statement.expression.fileOffset,
-              runtimeCheckedType: _returnContext,
+              runtimeCheckedType:
+                  inferrer.computeGreatestClosure2(_returnContext),
               isVoidAllowed: false)
             ..parent = statement;
         }
@@ -559,7 +560,8 @@
               statement.expression,
               fileOffset: statement.fileOffset,
               isVoidAllowed: true,
-              runtimeCheckedType: _returnContext);
+              runtimeCheckedType:
+                  inferrer.computeGreatestClosure(_returnContext));
           statement.expression = expression..parent = statement;
         }
 
diff --git a/pkg/front_end/testcases/general/issue42615.dart b/pkg/front_end/testcases/general/issue42615.dart
new file mode 100644
index 0000000..b18b51f
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue42615.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, 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 'dart:async';
+
+class Class<T> {
+  Class({FutureOr<List<T>> Function() a});
+}
+
+dynamic method() => null;
+
+main() {
+  Class(a: () async => method());
+}
diff --git a/pkg/front_end/testcases/general/issue42615.dart.outline.expect b/pkg/front_end/testcases/general/issue42615.dart.outline.expect
new file mode 100644
index 0000000..77a5b08
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue42615.dart.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+import "dart:async";
+
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  constructor •({() →* FutureOr<core::List<self::Class::T*>*>* a}) → self::Class<self::Class::T*>*
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+static method method() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/issue42615.dart.strong.expect b/pkg/front_end/testcases/general/issue42615.dart.strong.expect
new file mode 100644
index 0000000..2f569f8
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue42615.dart.strong.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+import "dart:async";
+
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  constructor •({() →* FutureOr<core::List<self::Class::T*>*>* a = #C1}) → self::Class<self::Class::T*>*
+    : super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+static method method() → dynamic
+  return null;
+static method main() → dynamic {
+  new self::Class::•<dynamic>(a: () → FutureOr<core::List<dynamic>*>* async => self::method() as{TypeError} FutureOr<core::List<dynamic>*>*);
+}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/general/issue42615.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue42615.dart.strong.transformed.expect
new file mode 100644
index 0000000..6057834
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue42615.dart.strong.transformed.expect
@@ -0,0 +1,57 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+import "dart:async";
+
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  constructor •({() →* FutureOr<core::List<self::Class::T*>*>* a = #C1}) → self::Class<self::Class::T*>*
+    : super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+static method method() → dynamic
+  return null;
+static method main() → dynamic {
+  new self::Class::•<dynamic>(a: () → FutureOr<core::List<dynamic>*>* /* originally async */ {
+    final asy::_AsyncAwaitCompleter<core::List<dynamic>*>* :async_completer = new asy::_AsyncAwaitCompleter::•<core::List<dynamic>*>();
+    FutureOr<core::List<dynamic>*>* :return_value;
+    dynamic :async_stack_trace;
+    (dynamic) →* dynamic :async_op_then;
+    (core::Object*, core::StackTrace*) →* dynamic :async_op_error;
+    core::int* :await_jump_var = 0;
+    dynamic :await_ctx_var;
+    function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+      try {
+        #L1:
+        {
+          :return_value = self::method() as{TypeError} FutureOr<core::List<dynamic>*>*;
+          break #L1;
+        }
+        asy::_completeOnAsyncReturn(:async_completer, :return_value);
+        return;
+      }
+      on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
+        :async_completer.{asy::Completer::completeError}(exception, stack_trace);
+      }
+    :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+    :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+    :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+    :async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
+    return :async_completer.{asy::Completer::future};
+  });
+}
+
+constants  {
+  #C1 = null
+}