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 |