L#4210. Skip empty return when inferring function literal return type when generator.

Bug: https://github.com/dart-lang/language/pull/4210
Change-Id: I098d80fe36ba6629d8613f2b4e80d4562c3232b5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/446183
Reviewed-by: Erik Ernst <eernst@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/body_inference_context.dart b/pkg/analyzer/lib/src/dart/resolver/body_inference_context.dart
index 3552b09..5384281 100644
--- a/pkg/analyzer/lib/src/dart/resolver/body_inference_context.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/body_inference_context.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
 
+/// See https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#function-literal-return-type-inference
 class BodyInferenceContext {
   final TypeSystemImpl _typeSystem;
   final bool isAsynchronous;
@@ -67,7 +68,12 @@
 
   void addReturnExpression(Expression? expression) {
     if (expression == null) {
-      _returnTypes.add(_typeProvider.nullType);
+      // If the enclosing function is not marked `sync*` or `async*`:
+      //   For each `return;` statement in the block, update
+      //   `T` to be `UP(Null, T)`.
+      if (!isGenerator) {
+        _returnTypes.add(_typeProvider.nullType);
+      }
     } else {
       var type = expression.typeOrThrow;
       if (isAsynchronous) {
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/function_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/function_expression_test.dart
index 58bad93..c2e24d3 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/function_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/function_expression_test.dart
@@ -661,6 +661,55 @@
     _assertReturnType('() async* {', 'Stream<int>');
   }
 
+  test_noContext_returnType_asyncStar_blockBody_hasReturn_empty() async {
+    await resolveTestCode(r'''
+var v = () async* {
+  yield 0;
+  return;
+};
+''');
+    _assertReturnType('() async* {', 'Stream<int>');
+  }
+
+  test_noContext_returnType_asyncStar_blockBody_hasReturn_noYield() async {
+    await resolveTestCode(r'''
+var v = () async* {
+  return;
+};
+''');
+    _assertReturnType('() async* {', 'Stream<dynamic>');
+  }
+
+  test_noContext_returnType_asyncStar_blockBody_lubNum() async {
+    await resolveTestCode(r'''
+var v = () async* {
+  yield 0;
+  yield 1.1;
+};
+''');
+    _assertReturnType('() async* {', 'Stream<num>');
+  }
+
+  test_noContext_returnType_asyncStar_blockBody_lubObject() async {
+    await resolveTestCode(r'''
+var v = () async* {
+  yield 0;
+  yield '';
+};
+''');
+    _assertReturnType('() async* {', 'Stream<Object>');
+  }
+
+  test_noContext_returnType_asyncStar_blockBody_lubWithNull() async {
+    await resolveTestCode(r'''
+var v = () async* {
+  yield 0;
+  yield null;
+};
+''');
+    _assertReturnType('() async* {', 'Stream<int?>');
+  }
+
   test_noContext_returnType_sync_blockBody() async {
     await resolveTestCode('''
 var v = () {
@@ -875,6 +924,55 @@
     _assertReturnType('() sync* {', 'Iterable<int>');
   }
 
+  test_noContext_returnType_syncStar_blockBody_hasReturn_empty() async {
+    await resolveTestCode(r'''
+var v = () sync* {
+  yield 0;
+  return;
+};
+''');
+    _assertReturnType('() sync* {', 'Iterable<int>');
+  }
+
+  test_noContext_returnType_syncStar_blockBody_hasReturn_noYield() async {
+    await resolveTestCode(r'''
+var v = () sync* {
+  return;
+};
+''');
+    _assertReturnType('() sync* {', 'Iterable<dynamic>');
+  }
+
+  test_noContext_returnType_syncStar_blockBody_lubNum() async {
+    await resolveTestCode(r'''
+var v = () sync* {
+  yield 0;
+  yield 1.1;
+};
+''');
+    _assertReturnType('() sync* {', 'Iterable<num>');
+  }
+
+  test_noContext_returnType_syncStar_blockBody_lubObject() async {
+    await resolveTestCode(r'''
+var v = () sync* {
+  yield 0;
+  yield '';
+};
+''');
+    _assertReturnType('() sync* {', 'Iterable<Object>');
+  }
+
+  test_noContext_returnType_syncStar_blockBody_lubWithNull() async {
+    await resolveTestCode(r'''
+var v = () sync* {
+  yield 0;
+  yield null;
+};
+''');
+    _assertReturnType('() sync* {', 'Iterable<int?>');
+  }
+
   test_targetBoundedByFunctionType_argumentTypeMismatch() async {
     await assertErrorsInCode(
       r'''