Relax return restrictions.

Change-Id: Ica37ff2ac1e206fb4dfc8448af7ecead2c031dd4
Reviewed-on: https://dart-review.googlesource.com/62220
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Leaf Petersen <leafp@google.com>
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index b470ac2..c4208bf 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -5726,35 +5726,63 @@
 
       var toType = expectedType;
       var fromType = expressionType;
-
-      if (isArrowFunction) {
-        if (_inAsync && toType.flattenFutures(_typeSystem).isVoid) {
-          return;
-        } else if (toType.isVoid) {
-          return;
-        }
+      if (_inAsync) {
+        toType = toType.flattenFutures(_typeSystem);
+        fromType = fromType.flattenFutures(_typeSystem);
       }
 
+      // Anything can be returned to `void` in an arrow bodied function
+      // or to `Future<void>` in an async arrow bodied function.
+      if (isArrowFunction && toType.isVoid) {
+        return;
+      }
+
+      // Anything can be returned to `dynamic`, or to `Future<dynamic>` in
+      // an async function.
       if (toType.isDynamic) {
         return;
       }
 
+      // Anything can be return to `Future<Null>` in an async function
+      if (_inAsync && toType.isDartCoreNull) {
+        return;
+      }
+
+      // If we're not in one of the `void` related special cases
+      // just check assignability.
+      if (!toType.isVoid && !fromType.isVoid) {
+        var checkWithType = (!_inAsync)
+            ? fromType
+            : _typeProvider.futureType.instantiate(<DartType>[fromType]);
+        if (_expressionIsAssignableAtType(
+            returnExpression, checkWithType, expectedType)) {
+          return;
+        }
+      }
+
+      // Void related special cases.  If the expression type flattens
+      // to `void`, and the expected type doesn't, then it's an error.
+      // Otherwise:
       if (toType.isVoid) {
-        if (fromType.isVoid) {
-          return;
-        }
-        if (!_inAsync && fromType.isDynamic ||
-            fromType.isDartCoreNull ||
-            fromType.isBottom) {
-          return;
-        }
-      } else if (!fromType.isVoid) {
-        if (_inAsync) {
-          fromType = _typeProvider.futureType
-              .instantiate(<DartType>[fromType.flattenFutures(_typeSystem)]);
-        }
-        if (_expressionIsAssignableAtType(returnExpression, fromType, toType)) {
-          return;
+        // In the case that the expected type is `void`
+        if (expectedType.isVoid) {
+          // Valid if the expression type is void, dynamic or Null
+          if (expressionType.isVoid ||
+              expressionType.isDynamic ||
+              expressionType.isDartCoreNull ||
+              expressionType.isBottom) {
+            return;
+          }
+        } else {
+          // The expected type is Future<void> or FutureOr<void>,
+          // and the return is valid if the expression type flattens
+          // to void, dynamic, or Null.
+          if (fromType.isVoid ||
+              fromType.isDynamic ||
+              fromType.isDartCoreNull ||
+              fromType.isBottom) {
+            return;
+          }
         }
       }
       reportTypeError();
diff --git a/pkg/vm/lib/frontend_server.dart b/pkg/vm/lib/frontend_server.dart
index 5c69abf..709d28e 100644
--- a/pkg/vm/lib/frontend_server.dart
+++ b/pkg/vm/lib/frontend_server.dart
@@ -714,7 +714,7 @@
       compiler.acceptLastDelta();
       await compiler.recompileDelta();
       compiler.acceptLastDelta();
-      return 0;
+      return;
     } finally {
       temp.deleteSync(recursive: true);
     }
diff --git a/tests/language_2/language_2.status b/tests/language_2/language_2.status
index 227ceb6..fbca329 100644
--- a/tests/language_2/language_2.status
+++ b/tests/language_2/language_2.status
@@ -300,7 +300,6 @@
 void/return_future_or_void_sync_error3_test: MissingCompileTimeError # https://github.com/dart-lang/sdk/issues/33218
 void/return_future_or_void_sync_error4_test/none: MissingStaticWarning # https://github.com/dart-lang/sdk/issues/33218
 void/return_future_void_async_error2_test: MissingCompileTimeError # https://github.com/dart-lang/sdk/issues/33218
-void/return_future_void_async_test: StaticWarning # https://github.com/dart-lang/sdk/issues/33218
 void/return_void_async_error0_test: MissingCompileTimeError # https://github.com/dart-lang/sdk/issues/33218
 void/return_void_async_error1_test: MissingCompileTimeError # https://github.com/dart-lang/sdk/issues/33218
 void/return_void_async_error2_test: MissingCompileTimeError # https://github.com/dart-lang/sdk/issues/33218
diff --git a/tests/language_2/void/return_future_future_or_void_async_test.dart b/tests/language_2/void/return_future_future_or_void_async_test.dart
index 81fb4da..68b65ad 100644
--- a/tests/language_2/void/return_future_future_or_void_async_test.dart
+++ b/tests/language_2/void/return_future_future_or_void_async_test.dart
@@ -8,8 +8,6 @@
 
 void main() {
   test1();
-  test2();
-  test3();
   test4();
   test5();
   test6();
@@ -20,16 +18,6 @@
 // Testing that a block bodied async function may have no return
 Future<FutureOr<void>> test1() async {}
 
-// Testing that a block bodied async function may return Future<void>
-Future<FutureOr<void>> test2([bool b]) async {
-  return null as Future<void>;
-}
-
-// Testing that a block bodied async function may return FutureOr<void>
-Future<FutureOr<void>> test3([bool b]) async {
-  return null as FutureOr<void>;
-}
-
 // Testing that a block bodied async function may return Future<FutureOr<void>>
 Future<FutureOr<void>> test4([bool b]) async {
   return null as Future<FutureOr<void>>;
@@ -54,5 +42,5 @@
 // Testing that a block bodied async function may return non-void
 // Future values
 Future<FutureOr<void>> test8() async {
-  return new Future.value(42);
+  return new Future<int>.value(42);
 }
diff --git a/tests/language_2/void/return_future_or_void_async_error0_test.dart b/tests/language_2/void/return_future_or_void_async_error0_test.dart
deleted file mode 100644
index c5115a7..0000000
--- a/tests/language_2/void/return_future_or_void_async_error0_test.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2018, 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';
-
-void voidValue = null;
-
-void main() {
-  test();
-}
-
-// Testing that a block bodied function may not return void
-FutureOr<void> test() async {
-  return /*@compile-error=unspecified*/ voidValue;
-}
diff --git a/tests/language_2/void/return_future_or_void_async_test.dart b/tests/language_2/void/return_future_or_void_async_test.dart
index dfdf1e7..151f337 100644
--- a/tests/language_2/void/return_future_or_void_async_test.dart
+++ b/tests/language_2/void/return_future_or_void_async_test.dart
@@ -11,8 +11,7 @@
   test1();
   test2();
   test3();
-  test4();
-  test5();
+  test6();
 }
 
 // Testing that a block bodied function may have an empty return
@@ -33,14 +32,7 @@
   return null as FutureOr<void>;
 }
 
-// Testing that a block bodied async function may return non-void
-// values
-FutureOr<void> test4() async {
-  return 42;
-}
-
-// Testing that a block bodied async function may return non-void
-// Future values
-FutureOr<void> test5() async {
-  return new Future.value(42);
+// Testing that a block bodied function may return void
+FutureOr<void> test6() async {
+  return voidValue;
 }
diff --git a/tests/language_2/void/return_future_void_async_error2_test.dart b/tests/language_2/void/return_future_void_async_error2_test.dart
deleted file mode 100644
index d31263e..0000000
--- a/tests/language_2/void/return_future_void_async_error2_test.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2018, 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';
-
-void voidValue = null;
-
-void main() {
-  test();
-}
-
-// Testing that a block bodied async function may return void
-Future<void> test() async {
-  return /*@compile-error=unspecified*/ voidValue;
-}
diff --git a/tests/language_2/void/return_future_void_async_test.dart b/tests/language_2/void/return_future_void_async_test.dart
index ba3f1f1..dae62ed 100644
--- a/tests/language_2/void/return_future_void_async_test.dart
+++ b/tests/language_2/void/return_future_void_async_test.dart
@@ -34,20 +34,17 @@
   return null as FutureOr<void>;
 }
 
-// Testing that a block bodied async function may return non-void
-// values
-Future<void> test4() async {
-  return 42;
+// Testing that a block bodied async function may return null
+Future<void> test4([bool b]) async {
+  return null;
 }
 
-// Testing that a block bodied async function may return non-void
-// Future values
-Future<void> test5() async {
-  return new Future.value(42);
+// Testing that a block bodied async function may return dynamic
+Future<void> test5([bool b]) async {
+  return null as dynamic;
 }
 
-// Testing that a block bodied async function return nested void
-// Future values
+// Testing that a block bodied async function return void
 Future<void> test6() async {
-  return null as Future<Future<void>>;
+  return voidValue;
 }
diff --git a/tests/language_2/void/return_void_async_error3_test.dart b/tests/language_2/void/return_void_async_error3_test.dart
deleted file mode 100644
index 27e691b..0000000
--- a/tests/language_2/void/return_void_async_error3_test.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2018, 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';
-
-void main() {
-  test();
-}
-
-// Testing that a block bodied async function may not return Future<void>
-void test() async {
-  return /*@compile-error=unspecified*/ null as Future<void>;
-}
diff --git a/tests/language_2/void/return_void_async_test.dart b/tests/language_2/void/return_void_async_test.dart
index bf10b9c..2f9966b 100644
--- a/tests/language_2/void/return_void_async_test.dart
+++ b/tests/language_2/void/return_void_async_test.dart
@@ -11,6 +11,8 @@
   test1();
   test2();
   test3();
+  test4();
+  test5();
 }
 
 // Testing that a block bodied async function may have an empty return
@@ -35,3 +37,13 @@
     return voidValue;
   }
 }
+
+// Testing that a block bodied async function may return Null
+void test4() async {
+  return null;
+}
+
+// Testing that a block bodied async function may return dynamic
+void test5() async {
+  return null as dynamic;
+}