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'''