| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 dev_compiler.src.checker.checker; | 5 library dev_compiler.src.checker.checker; |
| 6 | 6 |
| 7 import 'package:analyzer/analyzer.dart'; | 7 import 'package:analyzer/analyzer.dart'; |
| 8 import 'package:analyzer/src/generated/ast.dart'; | 8 import 'package:analyzer/src/generated/ast.dart'; |
| 9 import 'package:analyzer/src/generated/element.dart'; | 9 import 'package:analyzer/src/generated/element.dart'; |
| 10 import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType; | 10 import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType; |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 var field = node.fieldName; | 399 var field = node.fieldName; |
| 400 DartType staticType = rules.elementType(field.staticElement); | 400 DartType staticType = rules.elementType(field.staticElement); |
| 401 checkAssignment(node.expression, staticType); | 401 checkAssignment(node.expression, staticType); |
| 402 node.visitChildren(this); | 402 node.visitChildren(this); |
| 403 } | 403 } |
| 404 | 404 |
| 405 @override | 405 @override |
| 406 void visitForEachStatement(ForEachStatement node) { | 406 void visitForEachStatement(ForEachStatement node) { |
| 407 // Check that the expression is an Iterable. | 407 // Check that the expression is an Iterable. |
| 408 var expr = node.iterable; | 408 var expr = node.iterable; |
| 409 var iterableType = rules.provider.iterableType; | 409 var iterableType = node.awaitKeyword != null |
| 410 ? rules.provider.streamType |
| 411 : rules.provider.iterableType; |
| 410 var loopVariable = node.identifier != null | 412 var loopVariable = node.identifier != null |
| 411 ? node.identifier | 413 ? node.identifier |
| 412 : node.loopVariable.identifier; | 414 : node.loopVariable.identifier; |
| 413 var iteratorType = loopVariable.staticType; | 415 var iteratorType = loopVariable.staticType; |
| 414 var checkedType = iterableType.substitute4([iteratorType]); | 416 var checkedType = iterableType.substitute4([iteratorType]); |
| 415 checkAssignment(expr, checkedType); | 417 checkAssignment(expr, checkedType); |
| 416 node.visitChildren(this); | 418 node.visitChildren(this); |
| 417 } | 419 } |
| 418 | 420 |
| 419 @override | 421 @override |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 571 var element = node.staticElement; | 573 var element = node.staticElement; |
| 572 if (element == null) { | 574 if (element == null) { |
| 573 _recordMessage(new MissingTypeError(node)); | 575 _recordMessage(new MissingTypeError(node)); |
| 574 } else { | 576 } else { |
| 575 var type = node.staticElement.type; | 577 var type = node.staticElement.type; |
| 576 checkArgumentList(node.argumentList, type); | 578 checkArgumentList(node.argumentList, type); |
| 577 } | 579 } |
| 578 node.visitChildren(this); | 580 node.visitChildren(this); |
| 579 } | 581 } |
| 580 | 582 |
| 581 DartType _getExpectedReturnType(FunctionBody body, bool yieldStar) { | |
| 582 FunctionType functionType; | |
| 583 var parent = body.parent; | |
| 584 if (parent is Declaration) { | |
| 585 functionType = rules.elementType(parent.element); | |
| 586 } else { | |
| 587 assert(parent is FunctionExpression); | |
| 588 functionType = rules.getStaticType(parent); | |
| 589 } | |
| 590 | |
| 591 var type = functionType.returnType; | |
| 592 var provider = rules.provider; | |
| 593 | |
| 594 InterfaceType expectedType = null; | |
| 595 if (body.isAsynchronous) { | |
| 596 if (body.isGenerator) { | |
| 597 // Stream<T> -> T | |
| 598 expectedType = provider.streamType; | |
| 599 } else { | |
| 600 // Future<T> -> T | |
| 601 // TODO(vsm): Revisit with issue #228. | |
| 602 expectedType = provider.futureType; | |
| 603 } | |
| 604 } else { | |
| 605 if (body.isGenerator) { | |
| 606 // Iterable<T> -> T | |
| 607 expectedType = provider.iterableType; | |
| 608 } else { | |
| 609 // T -> T | |
| 610 return type; | |
| 611 } | |
| 612 } | |
| 613 if (yieldStar) { | |
| 614 if (type.isDynamic) { | |
| 615 // Ensure it's at least a Stream / Iterable. | |
| 616 return expectedType.substitute4([provider.dynamicType]); | |
| 617 } else { | |
| 618 // Analyzer will provide a separate error if expected type | |
| 619 // is not compatible with type. | |
| 620 return type; | |
| 621 } | |
| 622 } | |
| 623 if (type.isDynamic) { | |
| 624 return type; | |
| 625 } else if (type is InterfaceType && type.element == expectedType.element) { | |
| 626 return type.typeArguments[0]; | |
| 627 } else { | |
| 628 // Malformed type - fallback on analyzer error. | |
| 629 return null; | |
| 630 } | |
| 631 } | |
| 632 | |
| 633 FunctionBody _getFunctionBody(AstNode node) { | |
| 634 while (node is! FunctionBody) { | |
| 635 node = node.parent; | |
| 636 } | |
| 637 return node as FunctionBody; | |
| 638 } | |
| 639 | |
| 640 void _checkReturnOrYield(Expression expression, AstNode node, | 583 void _checkReturnOrYield(Expression expression, AstNode node, |
| 641 [bool yieldStar = false]) { | 584 {bool yieldStar: false}) { |
| 642 var body = _getFunctionBody(node); | 585 var body = node.getAncestor((n) => n is FunctionBody); |
| 643 var type = _getExpectedReturnType(body, yieldStar); | 586 var type = rules.getExpectedReturnType(body, yieldStar: yieldStar); |
| 644 if (type == null) { | 587 if (type == null) { |
| 645 // We have a type mismatch: the async/async*/sync* modifier does | 588 // We have a type mismatch: the async/async*/sync* modifier does |
| 646 // not match the return or yield type. We should have already gotten an | 589 // not match the return or yield type. We should have already gotten an |
| 647 // analyzer error in this case. | 590 // analyzer error in this case. |
| 648 return; | 591 return; |
| 649 } | 592 } |
| 650 // TODO(vsm): Enforce void or dynamic (to void?) when expression is null. | 593 // TODO(vsm): Enforce void or dynamic (to void?) when expression is null. |
| 651 if (expression != null) checkAssignment(expression, type); | 594 if (expression != null) checkAssignment(expression, type); |
| 652 } | 595 } |
| 653 | 596 |
| 654 @override | 597 @override |
| 655 void visitExpressionFunctionBody(ExpressionFunctionBody node) { | 598 void visitExpressionFunctionBody(ExpressionFunctionBody node) { |
| 656 _checkReturnOrYield(node.expression, node); | 599 _checkReturnOrYield(node.expression, node); |
| 657 node.visitChildren(this); | 600 node.visitChildren(this); |
| 658 } | 601 } |
| 659 | 602 |
| 660 @override | 603 @override |
| 661 void visitReturnStatement(ReturnStatement node) { | 604 void visitReturnStatement(ReturnStatement node) { |
| 662 _checkReturnOrYield(node.expression, node); | 605 _checkReturnOrYield(node.expression, node); |
| 663 node.visitChildren(this); | 606 node.visitChildren(this); |
| 664 } | 607 } |
| 665 | 608 |
| 666 @override | 609 @override |
| 667 void visitYieldStatement(YieldStatement node) { | 610 void visitYieldStatement(YieldStatement node) { |
| 668 _checkReturnOrYield(node.expression, node, node.star != null); | 611 _checkReturnOrYield(node.expression, node, yieldStar: node.star != null); |
| 669 node.visitChildren(this); | 612 node.visitChildren(this); |
| 670 } | 613 } |
| 671 | 614 |
| 672 @override | 615 @override |
| 673 void visitPropertyAccess(PropertyAccess node) { | 616 void visitPropertyAccess(PropertyAccess node) { |
| 674 var target = node.realTarget; | 617 var target = node.realTarget; |
| 675 if (rules.isDynamicTarget(target)) { | 618 if (rules.isDynamicTarget(target)) { |
| 676 _recordDynamicInvoke(node, target); | 619 _recordDynamicInvoke(node, target); |
| 677 } | 620 } |
| 678 node.visitChildren(this); | 621 node.visitChildren(this); |
| (...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 997 if (info is CoercionInfo) { | 940 if (info is CoercionInfo) { |
| 998 // TODO(jmesserly): if we're run again on the same AST, we'll produce the | 941 // TODO(jmesserly): if we're run again on the same AST, we'll produce the |
| 999 // same annotations. This should be harmless. This might go away once | 942 // same annotations. This should be harmless. This might go away once |
| 1000 // CodeChecker is integrated better with analyzer, as it will know that | 943 // CodeChecker is integrated better with analyzer, as it will know that |
| 1001 // checking has already been performed. | 944 // checking has already been performed. |
| 1002 // assert(CoercionInfo.get(info.node) == null); | 945 // assert(CoercionInfo.get(info.node) == null); |
| 1003 CoercionInfo.set(info.node, info); | 946 CoercionInfo.set(info.node, info); |
| 1004 } | 947 } |
| 1005 } | 948 } |
| 1006 } | 949 } |
| OLD | NEW |