From e6bdddfc8799908323101d876f0fa1e4ce4b59ac Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Wed, 7 Feb 2018 14:47:12 +0000 Subject: [PATCH] Further cleanup of wrapping/unwrapping of types during closure type inference. Addresses post-submit code review comments from https://dart-review.googlesource.com/c/sdk/+/39540. Change-Id: Id1a483dd23eef62738a13bec4bc002dd3ad6d30a Reviewed-on: https://dart-review.googlesource.com/39640 Reviewed-by: Kevin Millikin Commit-Queue: Paul Berry --- .../src/fasta/kernel/kernel_shadow_ast.dart | 19 ++----- .../fasta/type_inference/type_inferrer.dart | 53 ++++++++----------- 2 files changed, 28 insertions(+), 44 deletions(-) diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart index b135a64e33d..b1f8d42b18b 100644 --- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart +++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart @@ -1680,17 +1680,9 @@ class ShadowReturnStatement extends ReturnStatement implements ShadowStatement { void _inferStatement(ShadowTypeInferrer inferrer) { inferrer.listener.returnStatementEnter(this); var closureContext = inferrer.closureContext; - DartType typeContext; - if (!closureContext.isGenerator) { - typeContext = closureContext.unwrappedReturnOrYieldContext; - if (closureContext.isAsync) { - // In a non-generator async function, the type appearing on the RHS of - // a `return` statement may either be the closure context or Future<> - // applied to the closure context. We represent this using a context of - // `FutureOr`. - typeContext = inferrer.wrapFutureOrType(typeContext); - } - } + var typeContext = !closureContext.isGenerator + ? closureContext.returnOrYieldContext + : null; var inferredType = expression != null ? inferrer.inferExpression(expression, typeContext, true) : const VoidType(); @@ -2479,9 +2471,8 @@ class ShadowYieldStatement extends YieldStatement implements ShadowStatement { void _inferStatement(ShadowTypeInferrer inferrer) { inferrer.listener.yieldStatementEnter(this); var closureContext = inferrer.closureContext; - var typeContext = closureContext.isGenerator - ? closureContext.unwrappedReturnOrYieldContext - : null; + var typeContext = + closureContext.isGenerator ? closureContext.returnOrYieldContext : null; if (isYieldStar && typeContext != null) { typeContext = inferrer.wrapType( typeContext, 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 ddd21bfbb15..3cb2b703418 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 @@ -94,30 +94,31 @@ class ClosureContext { final bool isGenerator; - /// The type that is expected to appear on the RHS of a `return` or `yield` + /// The typing expectation for the subexpression of a `return` or `yield` /// statement inside the function. /// - /// For non-generator async functions, this is the "unwrapped" type (e.g. if - /// the function is expected to return `Future`, this is `int`) + /// For non-generator async functions, this will be a "FutureOr" type (since + /// it is permissible for such a function to return either a direct value or + /// a future). /// - /// For generator functions containing a `yield*` statement, the type that is - /// expected to appear on the RHS of the `yield*` statement is the result of - /// wrapping this type in `Stream` or `Iterator`, as appropriate. - final DartType unwrappedReturnOrYieldContext; + /// For generator functions containing a `yield*` statement, the expected type + /// for the subexpression of the `yield*` statement is the result of wrapping + /// this typing expectation in `Stream` or `Iterator`, as appropriate. + final DartType returnOrYieldContext; final bool _needToInferReturnType; final bool _needImplicitDowncasts; - /// The type that actually appeared on the RHS of a `return` or `yield` - /// statement inside the function. + /// The type that actually appeared as the subexpression of `return` or + /// `yield` statements inside the function. /// /// For non-generator async functions, this is the "unwrapped" type (e.g. if /// the function is expected to return `Future`, this is `int`). /// /// For generator functions containing a `yield*` statement, the type that - /// appeared on the RHS of the `yield*` statement was the result of wrapping - /// this type in `Stream` or `Iterator`, as appropriate. + /// appeared as the subexpression of the `yield*` statement was the result of + /// wrapping this type in `Stream` or `Iterator`, as appropriate. DartType _inferredUnwrappedReturnOrYieldType; factory ClosureContext( @@ -139,19 +140,15 @@ class ClosureContext { returnContext, inferrer.coreTypes.iterableClass); } } else if (isAsync) { - returnContext = - inferrer.typeSchemaEnvironment.unfutureType(returnContext); + returnContext = inferrer.wrapFutureOrType( + inferrer.typeSchemaEnvironment.unfutureType(returnContext)); } return new ClosureContext._(isAsync, isGenerator, returnContext, needToInferReturnType, needImplicitDowncasts); } - ClosureContext._( - this.isAsync, - this.isGenerator, - this.unwrappedReturnOrYieldContext, - this._needToInferReturnType, - this._needImplicitDowncasts); + ClosureContext._(this.isAsync, this.isGenerator, this.returnOrYieldContext, + this._needToInferReturnType, this._needImplicitDowncasts); /// Updates the inferred return type based on the presence of a return /// statement returning the given [type]. @@ -171,29 +168,25 @@ class ClosureContext { DartType inferReturnType(TypeInferrerImpl inferrer) { assert(_needToInferReturnType); - DartType inferredUnwrappedReturnOrYieldType = + DartType inferredType = inferrer.inferReturnType(_inferredUnwrappedReturnOrYieldType); - if (unwrappedReturnOrYieldContext != null && - !_analyzerSubtypeOf(inferrer, inferredUnwrappedReturnOrYieldType, - unwrappedReturnOrYieldContext)) { + if (returnOrYieldContext != null && + !_analyzerSubtypeOf(inferrer, inferredType, returnOrYieldContext)) { // If the inferred return type isn't a subtype of the context, we use the // context. - inferredUnwrappedReturnOrYieldType = unwrappedReturnOrYieldContext; + inferredType = returnOrYieldContext; } - return _wrapAsyncOrGenerator(inferrer, inferredUnwrappedReturnOrYieldType); + return _wrapAsyncOrGenerator(inferrer, inferredType); } void _updateInferredReturnType(TypeInferrerImpl inferrer, DartType type, Expression expression, int fileOffset, bool isReturn, bool isYieldStar) { if (_needImplicitDowncasts) { var expectedType = isYieldStar - ? _wrapAsyncOrGenerator(inferrer, unwrappedReturnOrYieldContext) - : unwrappedReturnOrYieldContext; + ? _wrapAsyncOrGenerator(inferrer, returnOrYieldContext) + : returnOrYieldContext; if (expectedType != null) { - if (!isGenerator && isAsync) { - expectedType = inferrer.wrapFutureOrType(expectedType); - } expectedType = greatestClosure(inferrer.coreTypes, expectedType); if (inferrer.checkAssignability( expectedType, type, expression, fileOffset) !=