Chromium Code Reviews| 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 496b821de8f7b985808eea72ca1e4ce9c9071f30..d66d60eff9e8d6fa3d27db4562ecc93d908509b1 100644 |
| --- a/pkg/analyzer/lib/src/generated/resolver.dart |
| +++ b/pkg/analyzer/lib/src/generated/resolver.dart |
| @@ -4602,12 +4602,20 @@ class InferenceContext { |
| final TypeSystem _typeSystem; |
| /** |
| + * When no context type is available, this will track the least upper bound |
| + * of all return statements in a lambda. |
| + * |
| + * This will always be kept in sync with [_returnStack]. |
| + */ |
| + final List<DartType> _inferredReturn = <DartType>[]; |
| + |
| + /** |
| * 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>[]; |
| + final List<DartType> _returnStack = <DartType>[]; |
| InferenceContext._(this._errorListener, TypeProvider typeProvider, |
| this._typeSystem, this._inferenceHints) |
| @@ -4638,19 +4646,49 @@ class InferenceContext { |
| /** |
| * Pop a return type off of the return stack. |
| + * |
| + * Also record any inferred return type using [setType], unless this node |
| + * already has a context type. This recorded type will be the least upper |
| + * bound of all types added with [addReturnType]. |
| */ |
| - void popReturnContext() { |
| - assert(_returnStack.isNotEmpty); |
| + void popReturnContext(BlockFunctionBody node) { |
| + assert(_returnStack.isNotEmpty && _inferredReturn.isNotEmpty); |
| if (_returnStack.isNotEmpty) { |
| _returnStack.removeLast(); |
| } |
| + if (_inferredReturn.isNotEmpty) { |
| + DartType inferred = _inferredReturn.removeLast(); |
| + if (!inferred.isBottom) { |
| + setType(node, inferred); |
| + } |
| + } |
| } |
| /** |
| - * Push a [returnType] onto the return stack. |
| + * Push a block function body's return type onto the return stack. |
| */ |
| - void pushReturnContext(DartType returnType) { |
| + void pushReturnContext(BlockFunctionBody node) { |
| + DartType returnType = getType(node); |
| _returnStack.add(returnType); |
| + _inferredReturn.add(BottomTypeImpl.instance); |
| + } |
| + |
| + /** |
| + * Records the type of the expression of a return statement. |
| + * |
| + * This will be used for inferring a block bodied lambda, if no context |
| + * type was available. |
| + */ |
| + void addReturnType(DartType type) { |
| + if (type == null || _returnStack.isEmpty) { |
| + return; |
| + } |
| + DartType context = _returnStack.last; |
| + if (context == null || context.isDynamic) { |
| + DartType inferred = _inferredReturn.last; |
| + inferred = _typeSystem.getLeastUpperBound(_typeProvider, type, inferred); |
| + _inferredReturn[_inferredReturn.length - 1] = inferred; |
| + } |
| } |
| /** |
| @@ -7657,11 +7695,11 @@ class ResolverVisitor extends ScopedVisitor { |
| Object visitBlockFunctionBody(BlockFunctionBody node) { |
| _overrideManager.enterScope(); |
| try { |
| - inferenceContext.pushReturnContext(InferenceContext.getType(node)); |
| + inferenceContext.pushReturnContext(node); |
| super.visitBlockFunctionBody(node); |
| } finally { |
| _overrideManager.exitScope(); |
| - inferenceContext.popReturnContext(); |
| + inferenceContext.popReturnContext(node); |
| } |
| return null; |
| } |
| @@ -8451,8 +8489,13 @@ class ResolverVisitor extends ScopedVisitor { |
| @override |
| Object visitReturnStatement(ReturnStatement node) { |
| - InferenceContext.setType(node.expression, inferenceContext.returnContext); |
| - return super.visitReturnStatement(node); |
| + Expression e = node.expression; |
| + InferenceContext.setType(e, inferenceContext.returnContext); |
| + super.visitReturnStatement(node); |
| + if (e != null) { |
| + inferenceContext.addReturnType(e.staticType); |
|
Leaf
2016/02/23 02:17:47
As it stands, I think that this will do the right
Jennifer Messerly
2016/02/23 17:41:46
Nice catch. Yeah, it seems like we should interpre
Jennifer Messerly
2016/02/24 00:20:40
Done.
|
| + } |
| + return null; |
| } |
| @override |