Specialize handling of returns and yields

Previously we used the same code to handle returns and yields.  The
code can be inlined and specialized.  This is a change in preparation
for detecting invalid returns in ClosureContext.handleReturn instead
of in TypeInferrer.ensureAssignable.

Change-Id: Ia6adc43ac1b95bb684e5df3757bcfd253434396a
Reviewed-on: https://dart-review.googlesource.com/71248
Reviewed-by: Daniel Hillerström <hillerstrom@google.com>
Commit-Queue: Kevin Millikin <kmillikin@google.com>
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 5d54fb7..b9e9545 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -234,54 +234,44 @@
   void handleReturn(TypeInferrerImpl inferrer, DartType type,
       Expression expression, int fileOffset, bool isArrow) {
     if (isGenerator) return;
-    _updateInferredReturnType(
-        inferrer, type, expression, fileOffset, true, false, isArrow);
+    if (inferrer.ensureAssignable(
+            returnOrYieldContext, type, expression, fileOffset,
+            isReturnFromAsync: isAsync,
+            isReturn: true,
+            declaredReturnType: declaredReturnType,
+            isArrow: isArrow) !=
+        null) {
+      type = greatestClosure(inferrer.coreTypes, returnOrYieldContext);
+    }
+    if (_needToInferReturnType) {
+      var unwrappedType = type;
+      if (isAsync) {
+        unwrappedType = inferrer.typeSchemaEnvironment.unfutureType(type);
+      }
+      if (_inferredUnwrappedReturnOrYieldType == null) {
+        _inferredUnwrappedReturnOrYieldType = unwrappedType;
+      } else {
+        _inferredUnwrappedReturnOrYieldType = inferrer.typeSchemaEnvironment
+            .getLeastUpperBound(
+                _inferredUnwrappedReturnOrYieldType, unwrappedType);
+      }
+    }
   }
 
   void handleYield(TypeInferrerImpl inferrer, bool isYieldStar, DartType type,
       Expression expression, int fileOffset) {
     if (!isGenerator) return;
-    _updateInferredReturnType(
-        inferrer, type, expression, fileOffset, false, isYieldStar, false);
-  }
-
-  DartType inferReturnType(TypeInferrerImpl inferrer) {
-    assert(_needToInferReturnType);
-    DartType inferredType =
-        inferrer.inferReturnType(_inferredUnwrappedReturnOrYieldType);
-    if (!_analyzerSubtypeOf(inferrer, inferredType, returnOrYieldContext)) {
-      // If the inferred return type isn't a subtype of the context, we use the
-      // context.
-      inferredType = greatestClosure(inferrer.coreTypes, returnOrYieldContext);
-    }
-
-    return _wrapAsyncOrGenerator(inferrer, inferredType);
-  }
-
-  void _updateInferredReturnType(
-      TypeInferrerImpl inferrer,
-      DartType type,
-      Expression expression,
-      int fileOffset,
-      bool isReturn,
-      bool isYieldStar,
-      bool isArrow) {
     var expectedType = isYieldStar
         ? _wrapAsyncOrGenerator(inferrer, returnOrYieldContext)
         : returnOrYieldContext;
     if (inferrer.ensureAssignable(expectedType, type, expression, fileOffset,
-            isReturnFromAsync: isAsync,
-            isReturn: isReturn,
-            declaredReturnType: declaredReturnType,
-            isArrow: isArrow) !=
+            isReturnFromAsync: isAsync) !=
         null) {
       type = greatestClosure(inferrer.coreTypes, expectedType);
     }
     if (_needToInferReturnType) {
       var unwrappedType = type;
-      if (isAsync && isReturn) {
-        unwrappedType = inferrer.typeSchemaEnvironment.unfutureType(type);
-      } else if (isYieldStar) {
+      if (isYieldStar) {
         unwrappedType = inferrer.getDerivedTypeArgumentOf(
                 type,
                 isAsync
@@ -299,6 +289,19 @@
     }
   }
 
+  DartType inferReturnType(TypeInferrerImpl inferrer) {
+    assert(_needToInferReturnType);
+    DartType inferredType =
+        inferrer.inferReturnType(_inferredUnwrappedReturnOrYieldType);
+    if (!_analyzerSubtypeOf(inferrer, inferredType, returnOrYieldContext)) {
+      // If the inferred return type isn't a subtype of the context, we use the
+      // context.
+      inferredType = greatestClosure(inferrer.coreTypes, returnOrYieldContext);
+    }
+
+    return _wrapAsyncOrGenerator(inferrer, inferredType);
+  }
+
   DartType _wrapAsyncOrGenerator(TypeInferrerImpl inferrer, DartType type) {
     if (isGenerator) {
       if (isAsync) {