| Index: pkg/analyzer/lib/src/generated/resolver.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
|
| index a52736d015cea04e0182ceda91145fac082f106a..0aa090c14b3f954d3e613fbd6895768fc741f4e9 100644
|
| --- a/pkg/analyzer/lib/src/generated/resolver.dart
|
| +++ b/pkg/analyzer/lib/src/generated/resolver.dart
|
| @@ -5415,6 +5415,8 @@ class InferenceContext {
|
| * A stack of return types for all of the enclosing
|
| * functions and methods.
|
| */
|
| + // TODO(leafp) Handle the implicit union type for Futures
|
| + // https://github.com/dart-lang/sdk/issues/25322
|
| List<DartType> _returnStack = <DartType>[];
|
|
|
| InferenceContext._(this._errorListener, TypeProvider typeProvider,
|
| @@ -5423,9 +5425,15 @@ class InferenceContext {
|
|
|
| /**
|
| * Get the return type of the current enclosing function, if any.
|
| + *
|
| + * The type returned for a function is the type that is expected
|
| + * to be used in a return or yield context. For ordinary functions
|
| + * this is the same as the return type of the function. For async
|
| + * functions returning Future<T> and for generator functions
|
| + * returning Stream<T> or Iterable<T>, this is T.
|
| */
|
| DartType get returnContext =>
|
| - (_returnStack.isNotEmpty) ? _returnStack.last : null;
|
| + _returnStack.isNotEmpty ? _returnStack.last : null;
|
|
|
| /**
|
| * Match type [t1] against type [t2] as follows.
|
| @@ -8359,8 +8367,10 @@ class ResolverVisitor extends ScopedVisitor {
|
|
|
| @override
|
| Object visitAwaitExpression(AwaitExpression node) {
|
| - //TODO(leafp): Handle the implicit union type here
|
| - DartType contextType = InferenceContext.getType(node);
|
| + // TODO(leafp): Handle the implicit union type here
|
| + // https://github.com/dart-lang/sdk/issues/25322
|
| + DartType contextType = StaticTypeAnalyzer.flattenFutures(
|
| + typeProvider, InferenceContext.getType(node));
|
| if (contextType != null) {
|
| InterfaceType futureT =
|
| typeProvider.futureType.substitute4([contextType]);
|
| @@ -8894,7 +8904,11 @@ class ResolverVisitor extends ScopedVisitor {
|
| DartType functionType = InferenceContext.getType(node);
|
| if (functionType is FunctionType) {
|
| _inferFormalParameterList(node.parameters, functionType);
|
| - InferenceContext.setType(node.body, functionType.returnType);
|
| + DartType returnType = _computeReturnOrYieldType(
|
| + functionType.returnType,
|
| + _enclosingFunction.isGenerator,
|
| + _enclosingFunction.isAsynchronous);
|
| + InferenceContext.setType(node.body, returnType);
|
| }
|
| super.visitFunctionExpression(node);
|
| } finally {
|
| @@ -9099,7 +9113,11 @@ class ResolverVisitor extends ScopedVisitor {
|
| ExecutableElement outerFunction = _enclosingFunction;
|
| try {
|
| _enclosingFunction = node.element;
|
| - InferenceContext.setType(node.body, node.element.type?.returnType);
|
| + DartType returnType = _computeReturnOrYieldType(
|
| + _enclosingFunction.type?.returnType,
|
| + _enclosingFunction.isGenerator,
|
| + _enclosingFunction.isAsynchronous);
|
| + InferenceContext.setType(node.body, returnType);
|
| super.visitMethodDeclaration(node);
|
| } finally {
|
| _enclosingFunction = outerFunction;
|
| @@ -9328,18 +9346,15 @@ class ResolverVisitor extends ScopedVisitor {
|
| // If we're not in a generator ([a]sync*, then we shouldn't have a yield.
|
| // so don't infer
|
| if (_enclosingFunction.isGenerator) {
|
| - // If this is a yield*, then we just propagate the return type downwards
|
| + // If this just a yield, then we just pass on the element type
|
| DartType type = returnType;
|
| - // If this just a yield, then we need to get the element type
|
| - if (node.star == null) {
|
| + if (node.star != null) {
|
| + // If this is a yield*, then we wrap the element return type
|
| // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
|
| - InterfaceType wrapperD = _enclosingFunction.isSynchronous
|
| - ? typeProvider.iterableDynamicType
|
| - : typeProvider.streamDynamicType;
|
| - // Match the types to instantiate the type arguments if possible
|
| - List<DartType> targs =
|
| - inferenceContext.matchTypes(wrapperD, returnType);
|
| - type = (targs?.length == 1) ? targs[0] : null;
|
| + InterfaceType wrapperType = _enclosingFunction.isSynchronous
|
| + ? typeProvider.iterableType
|
| + : typeProvider.streamType;
|
| + type = wrapperType.substitute4(<DartType>[type]);
|
| }
|
| InferenceContext.setType(node.expression, type);
|
| }
|
| @@ -9380,6 +9395,34 @@ class ResolverVisitor extends ScopedVisitor {
|
| }
|
|
|
| /**
|
| + * Given the declared return type of a function, compute the type of the
|
| + * values which should be returned or yielded as appropriate. If a type
|
| + * cannot be computed from the declared return type, return null.
|
| + */
|
| + DartType _computeReturnOrYieldType(
|
| + DartType declaredType, bool isGenerator, bool isAsynchronous) {
|
| + // Ordinary functions just return their declared types.
|
| + if (!isGenerator && !isAsynchronous) {
|
| + return declaredType;
|
| + }
|
| + if (isGenerator) {
|
| + if (declaredType is! InterfaceType) {
|
| + return null;
|
| + }
|
| + // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
|
| + InterfaceType rawType = isAsynchronous
|
| + ? typeProvider.streamDynamicType
|
| + : typeProvider.iterableDynamicType;
|
| + // Match the types to instantiate the type arguments if possible
|
| + List<DartType> typeArgs =
|
| + inferenceContext.matchTypes(rawType, declaredType);
|
| + return (typeArgs?.length == 1) ? typeArgs[0] : null;
|
| + }
|
| + // Must be asynchronous to reach here, so strip off any layers of Future
|
| + return StaticTypeAnalyzer.flattenFutures(typeProvider, declaredType);
|
| + }
|
| +
|
| + /**
|
| * The given expression is the expression used to compute the iterator for a
|
| * for-each statement. Attempt to compute the type of objects that will be
|
| * assigned to the loop variable and return that type. Return `null` if the
|
|
|