Issue 40538. Revert YieldStatement changes after reverting language spec decision.
Bug: https://github.com/dart-lang/sdk/issues/40538
Change-Id: Idd563a15dc1e17e1271f823c33d015c73f720874
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/136814
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
index f810900..9928a16 100644
--- a/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
@@ -17,11 +17,6 @@
class YieldStatementResolver {
final ResolverVisitor _resolver;
- /// The element type required by the declared return type of the enclosing
- /// function. Note, that for function expressions the declared return type
- /// can be obtained by means of type inference.
- DartType _elementType;
-
YieldStatementResolver({
@required ResolverVisitor resolver,
}) : _resolver = resolver;
@@ -75,66 +70,62 @@
///
/// This method should only be called in generator functions.
void _checkForYieldOfInvalidType(YieldStatement node, bool isYieldEach) {
- var expressionType = node.expression.staticType;
+ var declaredReturnType = _enclosingFunction.returnType;
- if (node.star == null) {
- if (!_typeSystem.isAssignableTo2(expressionType, _elementType)) {
- _errorReporter.reportErrorForNode(
- StaticTypeWarningCode.YIELD_OF_INVALID_TYPE,
- node.expression,
- [expressionType, _elementType],
- );
- }
- return;
+ var expression = node.expression;
+ var expressionType = expression.staticType;
+
+ DartType impliedReturnType;
+ if (isYieldEach) {
+ impliedReturnType = expressionType;
+ } else if (_enclosingFunction.isSynchronous) {
+ impliedReturnType = _typeProvider.iterableType2(expressionType);
+ } else {
+ impliedReturnType = _typeProvider.streamType2(expressionType);
}
- DartType yieldElementType;
- if (expressionType is InterfaceTypeImpl) {
- var sequenceType = expressionType.asInstanceOf(
- _typeProvider.iterableElement,
- );
- sequenceType ??= expressionType.asInstanceOf(
- _typeProvider.streamElement,
- );
- if (sequenceType != null) {
- yieldElementType = sequenceType.typeArguments[0];
- }
- }
-
- if (yieldElementType == null) {
- if (_typeSystem.isTop(expressionType) || expressionType.isDartCoreNull) {
- yieldElementType = DynamicTypeImpl.instance;
- } else {
+ if (declaredReturnType != null) {
+ if (!_typeSystem.isAssignableTo2(impliedReturnType, declaredReturnType)) {
_errorReporter.reportErrorForNode(
StaticTypeWarningCode.YIELD_OF_INVALID_TYPE,
- node.expression,
- [expressionType, _elementType],
+ expression,
+ [impliedReturnType, declaredReturnType],
);
return;
}
}
- if (!_typeSystem.isAssignableTo2(yieldElementType, _elementType)) {
- _errorReporter.reportErrorForNode(
- StaticTypeWarningCode.YIELD_OF_INVALID_TYPE,
- node.expression,
- [yieldElementType, _elementType],
- );
+ if (isYieldEach) {
+ // Since the declared return type might have been "dynamic", we need to
+ // also check that the implied return type is assignable to generic
+ // Iterable/Stream.
+ DartType requiredReturnType;
+ if (_enclosingFunction.isSynchronous) {
+ requiredReturnType = _typeProvider.iterableDynamicType;
+ } else {
+ requiredReturnType = _typeProvider.streamDynamicType;
+ }
+
+ if (!_typeSystem.isAssignableTo2(impliedReturnType, requiredReturnType)) {
+ _errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.YIELD_OF_INVALID_TYPE,
+ expression,
+ [impliedReturnType, requiredReturnType],
+ );
+ }
}
}
void _computeElementType(YieldStatement node) {
- _elementType = _resolver.inferenceContext.returnContext;
- if (_elementType != null) {
- var contextType = _elementType;
+ var elementType = _resolver.inferenceContext.returnContext;
+ if (elementType != null) {
+ var contextType = elementType;
if (node.star != null) {
contextType = _enclosingFunction.isSynchronous
- ? _typeProvider.iterableType2(_elementType)
- : _typeProvider.streamType2(_elementType);
+ ? _typeProvider.iterableType2(elementType)
+ : _typeProvider.streamType2(elementType);
}
InferenceContext.setType(node.expression, contextType);
- } else {
- _elementType ??= DynamicTypeImpl.instance;
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/yield_of_invalid_type_test.dart b/pkg/analyzer/test/src/diagnostics/yield_of_invalid_type_test.dart
index 7892e62..8963c73 100644
--- a/pkg/analyzer/test/src/diagnostics/yield_of_invalid_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/yield_of_invalid_type_test.dart
@@ -19,14 +19,18 @@
@reflectiveTest
class YieldOfInvalidTypeTest extends DriverResolutionTest {
test_none_asyncStar_dynamic_to_streamInt() async {
- await assertNoErrorsInCode('''
+ await assertErrorsInCode(
+ '''
import 'dart:async';
Stream<int> f() async* {
dynamic a = 0;
yield a;
}
-''');
+''',
+ expectedErrorsByNullability(nullable: [
+ error(StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, 72, 1),
+ ], legacy: []));
}
test_none_asyncStar_int_to_basic() async {
@@ -36,6 +40,7 @@
}
''', [
error(StaticTypeWarningCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE, 0, 3),
+ error(StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, 25, 1),
]);
}
@@ -99,12 +104,16 @@
}
test_none_syncStar_dynamic_to_iterableInt() async {
- await assertNoErrorsInCode('''
+ await assertErrorsInCode(
+ '''
Iterable<int> f() sync* {
dynamic a = 0;
yield a;
}
-''');
+''',
+ expectedErrorsByNullability(nullable: [
+ error(StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, 51, 1),
+ ], legacy: []));
}
test_none_syncStar_int_to_basic() async {
@@ -114,6 +123,7 @@
}
''', [
error(StaticTypeWarningCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE, 0, 3),
+ error(StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, 24, 1),
]);
}
@@ -217,23 +227,27 @@
}
test_star_asyncStar_iterableInt_to_dynamic() async {
- await assertNoErrorsInCode('''
+ await assertErrorsInCode('''
f() async* {
var a = <int>[];
yield* a;
}
-''');
+''', [
+ error(StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, 41, 1),
+ ]);
}
test_star_asyncStar_iterableInt_to_streamInt() async {
- await assertNoErrorsInCode('''
+ await assertErrorsInCode('''
import 'dart:async';
Stream<int> f() async* {
var a = <int>[];
yield* a;
}
-''');
+''', [
+ error(StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, 75, 1),
+ ]);
}
test_star_asyncStar_iterableString_to_streamInt() async {
@@ -262,7 +276,8 @@
}
test_star_asyncStar_streamDynamic_to_streamInt() async {
- await assertNoErrorsInCode('''
+ await assertErrorsInCode(
+ '''
import 'dart:async';
Stream<int> f() async* {
@@ -270,7 +285,10 @@
}
Stream g() => throw 0;
-''');
+''',
+ expectedErrorsByNullability(nullable: [
+ error(StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, 56, 3),
+ ], legacy: []));
}
test_star_asyncStar_streamInt_to_dynamic() async {
@@ -375,13 +393,17 @@
}
test_star_syncStar_iterableDynamic_to_iterableInt() async {
- await assertNoErrorsInCode('''
+ await assertErrorsInCode(
+ '''
Iterable<int> f() sync* {
yield* g();
}
Iterable g() => throw 0;
-''');
+''',
+ expectedErrorsByNullability(nullable: [
+ error(StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, 35, 3),
+ ], legacy: []));
}
test_star_syncStar_iterableInt_to_dynamic() async {
@@ -423,4 +445,7 @@
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
..contextFeatures = FeatureSet.forTesting(
sdkVersion: '2.7.0', additionalFeatures: [Feature.non_nullable]);
+
+ @override
+ bool get typeToStringWithNullability => true;
}