Simplify ClosureContext

There are some invariants about this class and some improvements we
can make:

  * needImplicitDowcasts is always true

  * returnContext is never null so neither is declaredReturnType or
    expectedType

  * ensureAssignable calls greatestClosure on the expected type so we
    don't have to

  * we don't need to unwrap the type of the subexpression unless we
    are inferring a return type based on it

Change-Id: I4eaf41f17dd9d5ad44143a04ef02fe11824b2aa7
Reviewed-on: https://dart-review.googlesource.com/71164
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 c53cd10..5d54fb7 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
@@ -191,8 +191,6 @@
 
   final bool _needToInferReturnType;
 
-  final bool _needImplicitDowncasts;
-
   /// The type that actually appeared as the subexpression of `return` or
   /// `yield` statements inside the function.
   ///
@@ -204,12 +202,9 @@
   /// wrapping this type in `Stream` or `Iterator`, as appropriate.
   DartType _inferredUnwrappedReturnOrYieldType;
 
-  factory ClosureContext(
-      TypeInferrerImpl inferrer,
-      AsyncMarker asyncMarker,
-      DartType returnContext,
-      bool needToInferReturnType,
-      bool needImplicitDowncasts) {
+  factory ClosureContext(TypeInferrerImpl inferrer, AsyncMarker asyncMarker,
+      DartType returnContext, bool needToInferReturnType) {
+    assert(returnContext != null);
     DartType declaredReturnType = returnContext;
     bool isAsync = asyncMarker == AsyncMarker.Async ||
         asyncMarker == AsyncMarker.AsyncStar;
@@ -228,18 +223,11 @@
           inferrer.typeSchemaEnvironment.unfutureType(returnContext));
     }
     return new ClosureContext._(isAsync, isGenerator, returnContext,
-        declaredReturnType, needToInferReturnType, needImplicitDowncasts);
+        declaredReturnType, needToInferReturnType);
   }
 
-  ClosureContext._(
-      this.isAsync,
-      this.isGenerator,
-      this.returnOrYieldContext,
-      this.declaredReturnType,
-      this._needToInferReturnType,
-      this._needImplicitDowncasts) {
-    assert(returnOrYieldContext != null);
-  }
+  ClosureContext._(this.isAsync, this.isGenerator, this.returnOrYieldContext,
+      this.declaredReturnType, this._needToInferReturnType) {}
 
   /// Updates the inferred return type based on the presence of a return
   /// statement returning the given [type].
@@ -261,8 +249,7 @@
     assert(_needToInferReturnType);
     DartType inferredType =
         inferrer.inferReturnType(_inferredUnwrappedReturnOrYieldType);
-    if (returnOrYieldContext != null &&
-        !_analyzerSubtypeOf(inferrer, inferredType, returnOrYieldContext)) {
+    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);
@@ -279,35 +266,29 @@
       bool isReturn,
       bool isYieldStar,
       bool isArrow) {
-    if (_needImplicitDowncasts) {
-      var expectedType = isYieldStar
-          ? _wrapAsyncOrGenerator(inferrer, returnOrYieldContext)
-          : returnOrYieldContext;
-      if (expectedType != null) {
-        expectedType = greatestClosure(inferrer.coreTypes, expectedType);
-        if (inferrer.ensureAssignable(
-                expectedType, type, expression, fileOffset,
-                isReturnFromAsync: isAsync,
-                isReturn: isReturn,
-                declaredReturnType: declaredReturnType,
-                isArrow: isArrow) !=
-            null) {
-          type = expectedType;
-        }
-      }
-    }
-    var unwrappedType = type;
-    if (isAsync && isReturn) {
-      unwrappedType = inferrer.typeSchemaEnvironment.unfutureType(type);
-    } else if (isYieldStar) {
-      unwrappedType = inferrer.getDerivedTypeArgumentOf(
-              type,
-              isAsync
-                  ? inferrer.coreTypes.streamClass
-                  : inferrer.coreTypes.iterableClass) ??
-          type;
+    var expectedType = isYieldStar
+        ? _wrapAsyncOrGenerator(inferrer, returnOrYieldContext)
+        : returnOrYieldContext;
+    if (inferrer.ensureAssignable(expectedType, type, expression, fileOffset,
+            isReturnFromAsync: isAsync,
+            isReturn: isReturn,
+            declaredReturnType: declaredReturnType,
+            isArrow: isArrow) !=
+        null) {
+      type = greatestClosure(inferrer.coreTypes, expectedType);
     }
     if (_needToInferReturnType) {
+      var unwrappedType = type;
+      if (isAsync && isReturn) {
+        unwrappedType = inferrer.typeSchemaEnvironment.unfutureType(type);
+      } else if (isYieldStar) {
+        unwrappedType = inferrer.getDerivedTypeArgumentOf(
+                type,
+                isAsync
+                    ? inferrer.coreTypes.streamClass
+                    : inferrer.coreTypes.iterableClass) ??
+            type;
+      }
       if (_inferredUnwrappedReturnOrYieldType == null) {
         _inferredUnwrappedReturnOrYieldType = unwrappedType;
       } else {
@@ -1255,8 +1236,7 @@
       Statement body) {
     assert(closureContext == null);
     this.helper = helper;
-    closureContext =
-        new ClosureContext(this, asyncMarker, returnType, false, true);
+    closureContext = new ClosureContext(this, asyncMarker, returnType, false);
     inferStatement(body);
     closureContext = null;
     this.helper = null;
@@ -1561,13 +1541,8 @@
     // to `xi` in `B` having type `Pi`.  This produces `B’`.
     bool needToSetReturnType = hasImplicitReturnType && strongMode;
     ClosureContext oldClosureContext = this.closureContext;
-    bool needImplicitDowncasts = returnContext != null;
     ClosureContext closureContext = new ClosureContext(
-        this,
-        function.asyncMarker,
-        returnContext,
-        needToSetReturnType,
-        needImplicitDowncasts);
+        this, function.asyncMarker, returnContext, needToSetReturnType);
     this.closureContext = closureContext;
     inferStatement(function.body);