| 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 646 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 var element = node.element as LocalVariableElementImpl; | 657 var element = node.element as LocalVariableElementImpl; |
| 658 var exprType = expr.staticType; | 658 var exprType = expr.staticType; |
| 659 if (exprType is InterfaceType) { | 659 if (exprType is InterfaceType) { |
| 660 var iteratedType = _findIteratedType(exprType); | 660 var iteratedType = _findIteratedType(exprType); |
| 661 if (iteratedType != null) { | 661 if (iteratedType != null) { |
| 662 element.type = iteratedType; | 662 element.type = iteratedType; |
| 663 } | 663 } |
| 664 } | 664 } |
| 665 } | 665 } |
| 666 | 666 |
| 667 Map<String, DartType> _objectMemberMap = null; |
| 668 |
| 669 Map<String, DartType> _getObjectMemberMap() { |
| 670 if (_objectMemberMap == null) { |
| 671 _objectMemberMap = new Map<String, DartType>(); |
| 672 var objectType = _typeProvider.objectType; |
| 673 var element = objectType.element; |
| 674 // Only record methods (including getters) with no parameters. As paramet
ers are contravariant wrt |
| 675 // type, using Object's version may be too strict. |
| 676 // Add instance methods. |
| 677 element.methods |
| 678 .where((method) => !method.isStatic && method.parameters.isEmpty) |
| 679 .forEach((method) { |
| 680 _objectMemberMap[method.name] = method.type; |
| 681 }); |
| 682 // Add getters. |
| 683 element.accessors |
| 684 .where((member) => !member.isStatic && member.isGetter) |
| 685 .forEach((member) { |
| 686 _objectMemberMap[member.name] = member.type.returnType; |
| 687 }); |
| 688 } |
| 689 return _objectMemberMap; |
| 690 } |
| 691 |
| 692 List<DartType> _sealedTypes = null; |
| 693 |
| 694 bool _isSealed(DartType t) { |
| 695 if (_sealedTypes == null) { |
| 696 // TODO(vsm): Use the analyzer's list - see dartbug.com/23125. |
| 697 _sealedTypes = <DartType>[ |
| 698 _typeProvider.nullType, |
| 699 _typeProvider.numType, |
| 700 _typeProvider.intType, |
| 701 _typeProvider.doubleType, |
| 702 _typeProvider.boolType, |
| 703 _typeProvider.stringType |
| 704 ]; |
| 705 } |
| 706 return _sealedTypes.contains(t); |
| 707 } |
| 708 |
| 667 @override // to propagate types to identifiers | 709 @override // to propagate types to identifiers |
| 668 visitMethodInvocation(MethodInvocation node) { | 710 visitMethodInvocation(MethodInvocation node) { |
| 669 // TODO(sigmund): follow up with analyzer team - why is this needed? | 711 // TODO(sigmund): follow up with analyzer team - why is this needed? |
| 670 visitSimpleIdentifier(node.methodName); | 712 visitSimpleIdentifier(node.methodName); |
| 671 super.visitMethodInvocation(node); | 713 super.visitMethodInvocation(node); |
| 672 | 714 |
| 715 // Search for Object methods. |
| 716 var objectMap = _getObjectMemberMap(); |
| 717 var name = node.methodName.name; |
| 718 if (node.staticType.isDynamic && |
| 719 objectMap.containsKey(name) && |
| 720 isDynamicTarget(node.target)) { |
| 721 var type = objectMap[name]; |
| 722 if (type is FunctionType && node.argumentList.arguments.isEmpty) { |
| 723 node.target.staticType = _typeProvider.objectType; |
| 724 node.methodName.staticType = type; |
| 725 // Only infer the type of the overall expression if we have an exact |
| 726 // type - e.g., a sealed type. Otherwise, it may be too strict. |
| 727 if (_isSealed(type.returnType)) { |
| 728 node.staticType = type.returnType; |
| 729 } |
| 730 } |
| 731 } |
| 732 |
| 673 var e = node.methodName.staticElement; | 733 var e = node.methodName.staticElement; |
| 674 if (e is FunctionElement && | 734 if (e is FunctionElement && |
| 675 e.library.name == '_foreign_helper' && | 735 e.library.name == '_foreign_helper' && |
| 676 e.name == 'JS') { | 736 e.name == 'JS') { |
| 677 // Fix types for JS builtin calls. | 737 // Fix types for JS builtin calls. |
| 678 // | 738 // |
| 679 // This code was taken from analyzer. It's not super sophisticated: | 739 // This code was taken from analyzer. It's not super sophisticated: |
| 680 // only looks for the type name in dart:core, so we just copy it here. | 740 // only looks for the type name in dart:core, so we just copy it here. |
| 681 // | 741 // |
| 682 // TODO(jmesserly): we'll likely need something that can handle a wider | 742 // TODO(jmesserly): we'll likely need something that can handle a wider |
| 683 // variety of types, especially when we get to JS interop. | 743 // variety of types, especially when we get to JS interop. |
| 684 var args = node.argumentList.arguments; | 744 var args = node.argumentList.arguments; |
| 685 if (args.isNotEmpty && args.first is SimpleStringLiteral) { | 745 if (args.isNotEmpty && args.first is SimpleStringLiteral) { |
| 686 var coreLib = _typeProvider.objectType.element.library; | 746 var coreLib = _typeProvider.objectType.element.library; |
| 687 var classElem = coreLib.getType(args.first.stringValue); | 747 var classElem = coreLib.getType(args.first.stringValue); |
| 688 if (classElem != null) node.staticType = classElem.type; | 748 if (classElem != null) node.staticType = classElem.type; |
| 689 } | 749 } |
| 690 } | 750 } |
| 691 } | 751 } |
| 692 | 752 |
| 753 void _inferObjectAccess( |
| 754 Expression node, Expression target, SimpleIdentifier id) { |
| 755 // Search for Object accesses. |
| 756 var objectMap = _getObjectMemberMap(); |
| 757 var name = id.name; |
| 758 if (node.staticType.isDynamic && |
| 759 objectMap.containsKey(name) && |
| 760 isDynamicTarget(target)) { |
| 761 target.staticType = _typeProvider.objectType; |
| 762 var type = objectMap[name]; |
| 763 id.staticType = type; |
| 764 // Only infer the type of the overall expression if we have an exact |
| 765 // type - e.g., a sealed type. Otherwise, it may be too strict. |
| 766 if (_isSealed(type)) { |
| 767 node.staticType = type; |
| 768 } |
| 769 } |
| 770 } |
| 771 |
| 772 @override |
| 773 visitPropertyAccess(PropertyAccess node) { |
| 774 super.visitPropertyAccess(node); |
| 775 |
| 776 _inferObjectAccess(node, node.target, node.propertyName); |
| 777 } |
| 778 |
| 779 @override |
| 780 visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 781 super.visitPrefixedIdentifier(node); |
| 782 |
| 783 _inferObjectAccess(node, node.prefix, node.identifier); |
| 784 } |
| 785 |
| 693 @override | 786 @override |
| 694 visitConditionalExpression(ConditionalExpression node) { | 787 visitConditionalExpression(ConditionalExpression node) { |
| 695 // TODO(vsm): The static type of a conditional should be the LUB of the | 788 // TODO(vsm): The static type of a conditional should be the LUB of the |
| 696 // then and else expressions. The analyzer appears to compute dynamic when | 789 // then and else expressions. The analyzer appears to compute dynamic when |
| 697 // one or the other is the null literal. Remove this fix once the | 790 // one or the other is the null literal. Remove this fix once the |
| 698 // corresponding analyzer bug is fixed: | 791 // corresponding analyzer bug is fixed: |
| 699 // https://code.google.com/p/dart/issues/detail?id=22854 | 792 // https://code.google.com/p/dart/issues/detail?id=22854 |
| 700 super.visitConditionalExpression(node); | 793 super.visitConditionalExpression(node); |
| 701 if (node.staticType.isDynamic) { | 794 if (node.staticType.isDynamic) { |
| 702 var thenExpr = node.thenExpression; | 795 var thenExpr = node.thenExpression; |
| 703 var elseExpr = node.elseExpression; | 796 var elseExpr = node.elseExpression; |
| 704 if (thenExpr.staticType.isBottom) { | 797 if (thenExpr.staticType.isBottom) { |
| 705 node.staticType = elseExpr.staticType; | 798 node.staticType = elseExpr.staticType; |
| 706 } else if (elseExpr.staticType.isBottom) { | 799 } else if (elseExpr.staticType.isBottom) { |
| 707 node.staticType = thenExpr.staticType; | 800 node.staticType = thenExpr.staticType; |
| 708 } | 801 } |
| 709 } | 802 } |
| 710 } | 803 } |
| 711 | 804 |
| 712 // Review note: no longer need to override visitFunctionExpression, this is | 805 // Review note: no longer need to override visitFunctionExpression, this is |
| 713 // handled by the analyzer internally. | 806 // handled by the analyzer internally. |
| 714 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? | 807 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? |
| 715 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression | 808 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression |
| 716 // type in a (...) => expr or just the written type? | 809 // type in a (...) => expr or just the written type? |
| 717 | 810 |
| 718 } | 811 } |
| OLD | NEW |