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 |