| 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 /// Encapsulates how to invoke the analyzer resolver and overrides how it | 5 /// Encapsulates how to invoke the analyzer resolver and overrides how it |
| 6 /// computes types on expressions to use our restricted set of types. | 6 /// computes types on expressions to use our restricted set of types. |
| 7 library dev_compiler.src.checker.resolver; | 7 library dev_compiler.src.checker.resolver; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
| 10 import 'package:analyzer/src/generated/ast.dart'; | 10 import 'package:analyzer/src/generated/ast.dart'; |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 visitor.overrideManager.currentScope = overrideScope; | 562 visitor.overrideManager.currentScope = overrideScope; |
| 563 visitor.nameScope = nameScope; | 563 visitor.nameScope = nameScope; |
| 564 } | 564 } |
| 565 } | 565 } |
| 566 | 566 |
| 567 /// Overrides the default [StaticTypeAnalyzer] to adjust rules that are stricter | 567 /// Overrides the default [StaticTypeAnalyzer] to adjust rules that are stricter |
| 568 /// in the restricted type system and to infer types for untyped local | 568 /// in the restricted type system and to infer types for untyped local |
| 569 /// variables. | 569 /// variables. |
| 570 class RestrictedStaticTypeAnalyzer extends StaticTypeAnalyzer { | 570 class RestrictedStaticTypeAnalyzer extends StaticTypeAnalyzer { |
| 571 final TypeProvider _typeProvider; | 571 final TypeProvider _typeProvider; |
| 572 Map<String, DartType> _objectMembers; |
| 572 | 573 |
| 573 RestrictedStaticTypeAnalyzer(ResolverVisitor r) | 574 RestrictedStaticTypeAnalyzer(ResolverVisitor r) |
| 574 : _typeProvider = r.typeProvider, | 575 : _typeProvider = r.typeProvider, |
| 575 super(r); | 576 super(r) { |
| 577 _objectMembers = getObjectMemberMap(_typeProvider); |
| 578 } |
| 576 | 579 |
| 577 static constructor(ResolverVisitor r) => new RestrictedStaticTypeAnalyzer(r); | 580 static constructor(ResolverVisitor r) => new RestrictedStaticTypeAnalyzer(r); |
| 578 | 581 |
| 579 @override // to infer type from initializers | 582 @override // to infer type from initializers |
| 580 visitVariableDeclaration(VariableDeclaration node) { | 583 visitVariableDeclaration(VariableDeclaration node) { |
| 581 _inferType(node); | 584 _inferType(node); |
| 582 return super.visitVariableDeclaration(node); | 585 return super.visitVariableDeclaration(node); |
| 583 } | 586 } |
| 584 | 587 |
| 585 /// Infer the type of a variable based on the initializer's type. | 588 /// Infer the type of a variable based on the initializer's type. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 var element = node.element as LocalVariableElementImpl; | 644 var element = node.element as LocalVariableElementImpl; |
| 642 var exprType = expr.staticType; | 645 var exprType = expr.staticType; |
| 643 if (exprType is InterfaceType) { | 646 if (exprType is InterfaceType) { |
| 644 var iteratedType = _findIteratedType(exprType); | 647 var iteratedType = _findIteratedType(exprType); |
| 645 if (iteratedType != null) { | 648 if (iteratedType != null) { |
| 646 element.type = iteratedType; | 649 element.type = iteratedType; |
| 647 } | 650 } |
| 648 } | 651 } |
| 649 } | 652 } |
| 650 | 653 |
| 651 Map<String, DartType> _objectMemberMap = null; | |
| 652 | |
| 653 Map<String, DartType> _getObjectMemberMap() { | |
| 654 if (_objectMemberMap == null) { | |
| 655 _objectMemberMap = new Map<String, DartType>(); | |
| 656 var objectType = _typeProvider.objectType; | |
| 657 var element = objectType.element; | |
| 658 // Only record methods (including getters) with no parameters. As paramet
ers are contravariant wrt | |
| 659 // type, using Object's version may be too strict. | |
| 660 // Add instance methods. | |
| 661 element.methods | |
| 662 .where((method) => !method.isStatic && method.parameters.isEmpty) | |
| 663 .forEach((method) { | |
| 664 _objectMemberMap[method.name] = method.type; | |
| 665 }); | |
| 666 // Add getters. | |
| 667 element.accessors | |
| 668 .where((member) => !member.isStatic && member.isGetter) | |
| 669 .forEach((member) { | |
| 670 _objectMemberMap[member.name] = member.type.returnType; | |
| 671 }); | |
| 672 } | |
| 673 return _objectMemberMap; | |
| 674 } | |
| 675 | |
| 676 List<DartType> _sealedTypes = null; | 654 List<DartType> _sealedTypes = null; |
| 677 | 655 |
| 678 bool _isSealed(DartType t) { | 656 bool _isSealed(DartType t) { |
| 679 if (_sealedTypes == null) { | 657 if (_sealedTypes == null) { |
| 680 // TODO(vsm): Use the analyzer's list - see dartbug.com/23125. | 658 // TODO(vsm): Use the analyzer's list - see dartbug.com/23125. |
| 681 _sealedTypes = <DartType>[ | 659 _sealedTypes = <DartType>[ |
| 682 _typeProvider.nullType, | 660 _typeProvider.nullType, |
| 683 _typeProvider.numType, | 661 _typeProvider.numType, |
| 684 _typeProvider.intType, | 662 _typeProvider.intType, |
| 685 _typeProvider.doubleType, | 663 _typeProvider.doubleType, |
| 686 _typeProvider.boolType, | 664 _typeProvider.boolType, |
| 687 _typeProvider.stringType | 665 _typeProvider.stringType |
| 688 ]; | 666 ]; |
| 689 } | 667 } |
| 690 return _sealedTypes.contains(t); | 668 return _sealedTypes.contains(t); |
| 691 } | 669 } |
| 692 | 670 |
| 693 @override // to propagate types to identifiers | 671 @override // to propagate types to identifiers |
| 694 visitMethodInvocation(MethodInvocation node) { | 672 visitMethodInvocation(MethodInvocation node) { |
| 695 // TODO(jmesserly): we rely on having a staticType propagated to the | 673 // TODO(jmesserly): we rely on having a staticType propagated to the |
| 696 // methodName identifier. This shouldn't be necessary for method calls, so | 674 // methodName identifier. This shouldn't be necessary for method calls, so |
| 697 // analyzer doesn't do it by default. Conceptually what we're doing here | 675 // analyzer doesn't do it by default. Conceptually what we're doing here |
| 698 // is asking for a tear off. We need this until we can fix #132, and rely | 676 // is asking for a tear off. We need this until we can fix #132, and rely |
| 699 // on `node.staticElement == null` instead of `rules.isDynamicCall(node)`. | 677 // on `node.staticElement == null` instead of `rules.isDynamicCall(node)`. |
| 700 visitSimpleIdentifier(node.methodName); | 678 visitSimpleIdentifier(node.methodName); |
| 701 | 679 |
| 702 super.visitMethodInvocation(node); | 680 super.visitMethodInvocation(node); |
| 703 | 681 |
| 704 // Search for Object methods. | 682 // Search for Object methods. |
| 705 var objectMap = _getObjectMemberMap(); | |
| 706 var name = node.methodName.name; | 683 var name = node.methodName.name; |
| 707 if (node.staticType.isDynamic && | 684 if (node.staticType.isDynamic && |
| 708 objectMap.containsKey(name) && | 685 _objectMembers.containsKey(name) && |
| 709 isDynamicTarget(node.target)) { | 686 isDynamicTarget(node.target)) { |
| 710 var type = objectMap[name]; | 687 var type = _objectMembers[name]; |
| 711 if (type is FunctionType && node.argumentList.arguments.isEmpty) { | 688 if (type is FunctionType && |
| 689 type.parameters.isEmpty && |
| 690 node.argumentList.arguments.isEmpty) { |
| 712 node.target.staticType = _typeProvider.objectType; | 691 node.target.staticType = _typeProvider.objectType; |
| 713 node.methodName.staticType = type; | 692 node.methodName.staticType = type; |
| 714 // Only infer the type of the overall expression if we have an exact | 693 // Only infer the type of the overall expression if we have an exact |
| 715 // type - e.g., a sealed type. Otherwise, it may be too strict. | 694 // type - e.g., a sealed type. Otherwise, it may be too strict. |
| 716 if (_isSealed(type.returnType)) { | 695 if (_isSealed(type.returnType)) { |
| 717 node.staticType = type.returnType; | 696 node.staticType = type.returnType; |
| 718 } | 697 } |
| 719 } | 698 } |
| 720 } | 699 } |
| 721 | 700 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 735 var coreLib = _typeProvider.objectType.element.library; | 714 var coreLib = _typeProvider.objectType.element.library; |
| 736 var classElem = coreLib.getType(args.first.stringValue); | 715 var classElem = coreLib.getType(args.first.stringValue); |
| 737 if (classElem != null) node.staticType = classElem.type; | 716 if (classElem != null) node.staticType = classElem.type; |
| 738 } | 717 } |
| 739 } | 718 } |
| 740 } | 719 } |
| 741 | 720 |
| 742 void _inferObjectAccess( | 721 void _inferObjectAccess( |
| 743 Expression node, Expression target, SimpleIdentifier id) { | 722 Expression node, Expression target, SimpleIdentifier id) { |
| 744 // Search for Object accesses. | 723 // Search for Object accesses. |
| 745 var objectMap = _getObjectMemberMap(); | |
| 746 var name = id.name; | 724 var name = id.name; |
| 747 if (node.staticType.isDynamic && | 725 if (node.staticType.isDynamic && |
| 748 objectMap.containsKey(name) && | 726 _objectMembers.containsKey(name) && |
| 749 isDynamicTarget(target)) { | 727 isDynamicTarget(target)) { |
| 750 target.staticType = _typeProvider.objectType; | 728 target.staticType = _typeProvider.objectType; |
| 751 var type = objectMap[name]; | 729 var type = _objectMembers[name]; |
| 752 id.staticType = type; | 730 id.staticType = type; |
| 753 // Only infer the type of the overall expression if we have an exact | 731 // Only infer the type of the overall expression if we have an exact |
| 754 // type - e.g., a sealed type. Otherwise, it may be too strict. | 732 // type - e.g., a sealed type. Otherwise, it may be too strict. |
| 755 if (_isSealed(type)) { | 733 if (_isSealed(type)) { |
| 756 node.staticType = type; | 734 node.staticType = type; |
| 757 } | 735 } |
| 758 } | 736 } |
| 759 } | 737 } |
| 760 | 738 |
| 761 @override | 739 @override |
| (...skipping 29 matching lines...) Expand all Loading... |
| 791 } | 769 } |
| 792 } | 770 } |
| 793 | 771 |
| 794 // Review note: no longer need to override visitFunctionExpression, this is | 772 // Review note: no longer need to override visitFunctionExpression, this is |
| 795 // handled by the analyzer internally. | 773 // handled by the analyzer internally. |
| 796 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? | 774 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? |
| 797 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression | 775 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression |
| 798 // type in a (...) => expr or just the written type? | 776 // type in a (...) => expr or just the written type? |
| 799 | 777 |
| 800 } | 778 } |
| OLD | NEW |