Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: pkg/analyzer/lib/src/generated/resolver.dart

Issue 1724543002: fix #25487, infer block lambdas from return statements (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.generated.resolver; 5 library analyzer.src.generated.resolver;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
(...skipping 4584 matching lines...) Expand 10 before | Expand all | Expand 10 after
4595 * Type provider, needed for type matching. 4595 * Type provider, needed for type matching.
4596 */ 4596 */
4597 final TypeProvider _typeProvider; 4597 final TypeProvider _typeProvider;
4598 4598
4599 /** 4599 /**
4600 * The type system in use. 4600 * The type system in use.
4601 */ 4601 */
4602 final TypeSystem _typeSystem; 4602 final TypeSystem _typeSystem;
4603 4603
4604 /** 4604 /**
4605 * When no context type is available, this will track the least upper bound
4606 * of all return statements in a lambda.
4607 *
4608 * This will always be kept in sync with [_returnStack].
4609 */
4610 final List<DartType> _inferredReturn = <DartType>[];
4611
4612 /**
4605 * A stack of return types for all of the enclosing 4613 * A stack of return types for all of the enclosing
4606 * functions and methods. 4614 * functions and methods.
4607 */ 4615 */
4608 // TODO(leafp) Handle the implicit union type for Futures 4616 // TODO(leafp) Handle the implicit union type for Futures
4609 // https://github.com/dart-lang/sdk/issues/25322 4617 // https://github.com/dart-lang/sdk/issues/25322
4610 List<DartType> _returnStack = <DartType>[]; 4618 final List<DartType> _returnStack = <DartType>[];
4611 4619
4612 InferenceContext._(this._errorListener, TypeProvider typeProvider, 4620 InferenceContext._(this._errorListener, TypeProvider typeProvider,
4613 this._typeSystem, this._inferenceHints) 4621 this._typeSystem, this._inferenceHints)
4614 : _typeProvider = typeProvider; 4622 : _typeProvider = typeProvider;
4615 4623
4616 /** 4624 /**
4617 * Get the return type of the current enclosing function, if any. 4625 * Get the return type of the current enclosing function, if any.
4618 * 4626 *
4619 * The type returned for a function is the type that is expected 4627 * The type returned for a function is the type that is expected
4620 * to be used in a return or yield context. For ordinary functions 4628 * to be used in a return or yield context. For ordinary functions
(...skipping 10 matching lines...) Expand all
4631 * of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>` 4639 * of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>`
4632 * If the supertype exists, use the constraints `S0 <: S0', ... Sm <: Sm'` 4640 * If the supertype exists, use the constraints `S0 <: S0', ... Sm <: Sm'`
4633 * to derive a concrete instantation for I of the form `<T0, ..., Tn>`, 4641 * to derive a concrete instantation for I of the form `<T0, ..., Tn>`,
4634 * such that `I<T0, .., Tn> <: t2` 4642 * such that `I<T0, .., Tn> <: t2`
4635 */ 4643 */
4636 List<DartType> matchTypes(DartType t1, DartType t2) => 4644 List<DartType> matchTypes(DartType t1, DartType t2) =>
4637 (t1 is InterfaceType && t2 is InterfaceType) ? _matchTypes(t1, t2) : null; 4645 (t1 is InterfaceType && t2 is InterfaceType) ? _matchTypes(t1, t2) : null;
4638 4646
4639 /** 4647 /**
4640 * Pop a return type off of the return stack. 4648 * Pop a return type off of the return stack.
4649 *
4650 * Also record any inferred return type using [setType], unless this node
4651 * already has a context type. This recorded type will be the least upper
4652 * bound of all types added with [addReturnType].
4641 */ 4653 */
4642 void popReturnContext() { 4654 void popReturnContext(BlockFunctionBody node) {
4643 assert(_returnStack.isNotEmpty); 4655 assert(_returnStack.isNotEmpty && _inferredReturn.isNotEmpty);
4644 if (_returnStack.isNotEmpty) { 4656 if (_returnStack.isNotEmpty) {
4645 _returnStack.removeLast(); 4657 _returnStack.removeLast();
4646 } 4658 }
4659 if (_inferredReturn.isNotEmpty) {
4660 DartType inferred = _inferredReturn.removeLast();
4661 if (!inferred.isBottom) {
4662 setType(node, inferred);
4663 }
4664 }
4647 } 4665 }
4648 4666
4649 /** 4667 /**
4650 * Push a [returnType] onto the return stack. 4668 * Push a block function body's return type onto the return stack.
4651 */ 4669 */
4652 void pushReturnContext(DartType returnType) { 4670 void pushReturnContext(BlockFunctionBody node) {
4671 DartType returnType = getType(node);
4653 _returnStack.add(returnType); 4672 _returnStack.add(returnType);
4673 _inferredReturn.add(BottomTypeImpl.instance);
4654 } 4674 }
4655 4675
4656 /** 4676 /**
4677 * Records the type of the expression of a return statement.
4678 *
4679 * This will be used for inferring a block bodied lambda, if no context
4680 * type was available.
4681 */
4682 void addReturnType(DartType type) {
4683 if (type == null || _returnStack.isEmpty) {
4684 return;
4685 }
4686 DartType context = _returnStack.last;
4687 if (context == null || context.isDynamic) {
4688 DartType inferred = _inferredReturn.last;
4689 inferred = _typeSystem.getLeastUpperBound(_typeProvider, type, inferred);
4690 _inferredReturn[_inferredReturn.length - 1] = inferred;
4691 }
4692 }
4693
4694 /**
4657 * Place an info node into the error stream indicating that a 4695 * Place an info node into the error stream indicating that a
4658 * [type] has been inferred as the type of [node]. 4696 * [type] has been inferred as the type of [node].
4659 */ 4697 */
4660 void recordInference(Expression node, DartType type) { 4698 void recordInference(Expression node, DartType type) {
4661 StaticInfo info = InferredType.create(_typeSystem, node, type); 4699 StaticInfo info = InferredType.create(_typeSystem, node, type);
4662 if (!_inferenceHints || info == null) { 4700 if (!_inferenceHints || info == null) {
4663 return; 4701 return;
4664 } 4702 }
4665 AnalysisError error = info.toAnalysisError(); 4703 AnalysisError error = info.toAnalysisError();
4666 _errorListener.onError(error); 4704 _errorListener.onError(error);
(...skipping 2983 matching lines...) Expand 10 before | Expand all | Expand 10 after
7650 } 7688 }
7651 node.accept(elementResolver); 7689 node.accept(elementResolver);
7652 node.accept(typeAnalyzer); 7690 node.accept(typeAnalyzer);
7653 return null; 7691 return null;
7654 } 7692 }
7655 7693
7656 @override 7694 @override
7657 Object visitBlockFunctionBody(BlockFunctionBody node) { 7695 Object visitBlockFunctionBody(BlockFunctionBody node) {
7658 _overrideManager.enterScope(); 7696 _overrideManager.enterScope();
7659 try { 7697 try {
7660 inferenceContext.pushReturnContext(InferenceContext.getType(node)); 7698 inferenceContext.pushReturnContext(node);
7661 super.visitBlockFunctionBody(node); 7699 super.visitBlockFunctionBody(node);
7662 } finally { 7700 } finally {
7663 _overrideManager.exitScope(); 7701 _overrideManager.exitScope();
7664 inferenceContext.popReturnContext(); 7702 inferenceContext.popReturnContext(node);
7665 } 7703 }
7666 return null; 7704 return null;
7667 } 7705 }
7668 7706
7669 @override 7707 @override
7670 Object visitBreakStatement(BreakStatement node) { 7708 Object visitBreakStatement(BreakStatement node) {
7671 // 7709 //
7672 // We do not visit the label because it needs to be visited in the context 7710 // We do not visit the label because it needs to be visited in the context
7673 // of the statement. 7711 // of the statement.
7674 // 7712 //
(...skipping 769 matching lines...) Expand 10 before | Expand all | Expand 10 after
8444 // 8482 //
8445 InferenceContext.setType(node.argumentList, node.staticElement?.type); 8483 InferenceContext.setType(node.argumentList, node.staticElement?.type);
8446 safelyVisit(node.argumentList); 8484 safelyVisit(node.argumentList);
8447 node.accept(elementResolver); 8485 node.accept(elementResolver);
8448 node.accept(typeAnalyzer); 8486 node.accept(typeAnalyzer);
8449 return null; 8487 return null;
8450 } 8488 }
8451 8489
8452 @override 8490 @override
8453 Object visitReturnStatement(ReturnStatement node) { 8491 Object visitReturnStatement(ReturnStatement node) {
8454 InferenceContext.setType(node.expression, inferenceContext.returnContext); 8492 Expression e = node.expression;
8455 return super.visitReturnStatement(node); 8493 InferenceContext.setType(e, inferenceContext.returnContext);
8494 super.visitReturnStatement(node);
8495 if (e != null) {
8496 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.
8497 }
8498 return null;
8456 } 8499 }
8457 8500
8458 @override 8501 @override
8459 Object visitShowCombinator(ShowCombinator node) => null; 8502 Object visitShowCombinator(ShowCombinator node) => null;
8460 8503
8461 @override 8504 @override
8462 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { 8505 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
8463 // 8506 //
8464 // We visit the argument list, but do not visit the optional identifier 8507 // We visit the argument list, but do not visit the optional identifier
8465 // because it needs to be visited in the context of the constructor 8508 // because it needs to be visited in the context of the constructor
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
8566 _implicitLabelScope = outerImplicitScope; 8609 _implicitLabelScope = outerImplicitScope;
8567 } 8610 }
8568 // TODO(brianwilkerson) If the loop can only be exited because the condition 8611 // TODO(brianwilkerson) If the loop can only be exited because the condition
8569 // is false, then propagateFalseState(condition); 8612 // is false, then propagateFalseState(condition);
8570 node.accept(elementResolver); 8613 node.accept(elementResolver);
8571 node.accept(typeAnalyzer); 8614 node.accept(typeAnalyzer);
8572 return null; 8615 return null;
8573 } 8616 }
8574 8617
8575 @override 8618 @override
8576 Object visitYieldStatement(YieldStatement node) { 8619 Object visitYieldStatement(YieldStatement node) {
Leaf 2016/02/23 02:17:47 It seems like there's an analogous inference for y
Jennifer Messerly 2016/02/23 17:41:46 Good catch. Completely forgot that sync*/async* co
Jennifer Messerly 2016/02/24 00:20:40 Done. This one was a little tricky, in particular
8577 DartType returnType = inferenceContext.returnContext; 8620 DartType returnType = inferenceContext.returnContext;
8578 if (returnType != null && _enclosingFunction != null) { 8621 if (returnType != null && _enclosingFunction != null) {
8579 // If we're not in a generator ([a]sync*, then we shouldn't have a yield. 8622 // If we're not in a generator ([a]sync*, then we shouldn't have a yield.
8580 // so don't infer 8623 // so don't infer
8581 if (_enclosingFunction.isGenerator) { 8624 if (_enclosingFunction.isGenerator) {
8582 // If this just a yield, then we just pass on the element type 8625 // If this just a yield, then we just pass on the element type
8583 DartType type = returnType; 8626 DartType type = returnType;
8584 if (node.star != null) { 8627 if (node.star != null) {
8585 // If this is a yield*, then we wrap the element return type 8628 // If this is a yield*, then we wrap the element return type
8586 // If it's synchronous, we expect Iterable<T>, otherwise Stream<T> 8629 // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
(...skipping 4196 matching lines...) Expand 10 before | Expand all | Expand 10 after
12783 nonFields.add(node); 12826 nonFields.add(node);
12784 return null; 12827 return null;
12785 } 12828 }
12786 12829
12787 @override 12830 @override
12788 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); 12831 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this);
12789 12832
12790 @override 12833 @override
12791 Object visitWithClause(WithClause node) => null; 12834 Object visitWithClause(WithClause node) => null;
12792 } 12835 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698