Chromium Code Reviews| 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> _nonExtendableTypes = null; | |
| 693 | |
| 694 bool _isExtendable(DartType t) { | |
| 695 if (_nonExtendableTypes == null) { | |
| 696 // TODO(vsm): Use the analyzer's list - see dartbug.com/23125. | |
| 697 _nonExtendableTypes = <DartType>[ | |
| 698 _typeProvider.nullType, | |
| 699 _typeProvider.numType, | |
| 700 _typeProvider.intType, | |
| 701 _typeProvider.doubleType, | |
| 702 _typeProvider.boolType, | |
| 703 _typeProvider.stringType | |
| 704 ]; | |
| 705 } | |
| 706 return !_nonExtendableTypes.contains(t); | |
|
Jennifer Messerly
2015/04/07 19:05:49
whenever you're calling _isExtendable it's being i
vsm
2015/04/07 19:48:46
Done.
| |
| 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 && objectMap.containsKey(name)) { | |
| 719 var target = node.target; | |
| 720 if (target is SimpleIdentifier && | |
|
Jennifer Messerly
2015/04/07 19:05:49
why does target need to be a SimpleIdentifier? doe
vsm
2015/04/07 19:48:46
Good point. Fixed and test added.
| |
| 721 target.staticElement is! PrefixElement) { | |
|
Jennifer Messerly
2015/04/07 19:05:49
follow up to above suggestion, I wonder if somethi
vsm
2015/04/07 19:48:46
It cleans it up. Done.
| |
| 722 var type = objectMap[name]; | |
| 723 if (type is FunctionType && node.argumentList.arguments.isEmpty) { | |
| 724 node.methodName.staticType = type; | |
| 725 if (!_isExtendable(type.returnType)) { | |
| 726 // Don't infer the type of the overall expression in this case - | |
| 727 // it may be too strict. | |
|
Jennifer Messerly
2015/04/07 19:05:49
can this actually happen? I thought we didn't allo
vsm
2015/04/07 19:48:46
Note: my comment was in a confusing place - fixed
| |
| 728 node.staticType = type.returnType; | |
| 729 } | |
| 730 } | |
| 731 } | |
| 732 } | |
| 733 | |
| 673 var e = node.methodName.staticElement; | 734 var e = node.methodName.staticElement; |
| 674 if (e is FunctionElement && | 735 if (e is FunctionElement && |
| 675 e.library.name == '_foreign_helper' && | 736 e.library.name == '_foreign_helper' && |
| 676 e.name == 'JS') { | 737 e.name == 'JS') { |
| 677 // Fix types for JS builtin calls. | 738 // Fix types for JS builtin calls. |
| 678 // | 739 // |
| 679 // This code was taken from analyzer. It's not super sophisticated: | 740 // 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. | 741 // only looks for the type name in dart:core, so we just copy it here. |
| 681 // | 742 // |
| 682 // TODO(jmesserly): we'll likely need something that can handle a wider | 743 // TODO(jmesserly): we'll likely need something that can handle a wider |
| 683 // variety of types, especially when we get to JS interop. | 744 // variety of types, especially when we get to JS interop. |
| 684 var args = node.argumentList.arguments; | 745 var args = node.argumentList.arguments; |
| 685 if (args.isNotEmpty && args.first is SimpleStringLiteral) { | 746 if (args.isNotEmpty && args.first is SimpleStringLiteral) { |
| 686 var coreLib = _typeProvider.objectType.element.library; | 747 var coreLib = _typeProvider.objectType.element.library; |
| 687 var classElem = coreLib.getType(args.first.stringValue); | 748 var classElem = coreLib.getType(args.first.stringValue); |
| 688 if (classElem != null) node.staticType = classElem.type; | 749 if (classElem != null) node.staticType = classElem.type; |
| 689 } | 750 } |
| 690 } | 751 } |
| 691 } | 752 } |
| 692 | 753 |
| 754 void _inferObjectAccess( | |
| 755 Expression node, Expression target, SimpleIdentifier id) { | |
| 756 // Search for Object accesses. | |
| 757 var objectMap = _getObjectMemberMap(); | |
| 758 var name = id.name; | |
| 759 if (node.staticType.isDynamic && objectMap.containsKey(name)) { | |
| 760 if (target is SimpleIdentifier && | |
| 761 target.staticElement is! PrefixElement) { | |
| 762 var type = objectMap[name]; | |
| 763 id.staticType = type; | |
| 764 if (!_isExtendable(type)) { | |
| 765 // Don't infer the type of the overall expression in this case - | |
| 766 // it may be too strict. | |
| 767 node.staticType = type; | |
| 768 } | |
| 769 } | |
| 770 } | |
| 771 } | |
| 772 | |
| 773 @override | |
| 774 visitPropertyAccess(PropertyAccess node) { | |
| 775 super.visitPropertyAccess(node); | |
| 776 | |
| 777 _inferObjectAccess(node, node.target, node.propertyName); | |
| 778 } | |
| 779 | |
| 780 @override | |
| 781 visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 782 super.visitPrefixedIdentifier(node); | |
| 783 | |
| 784 _inferObjectAccess(node, node.prefix, node.identifier); | |
| 785 } | |
| 786 | |
| 693 @override | 787 @override |
| 694 visitConditionalExpression(ConditionalExpression node) { | 788 visitConditionalExpression(ConditionalExpression node) { |
| 695 // TODO(vsm): The static type of a conditional should be the LUB of the | 789 // 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 | 790 // 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 | 791 // one or the other is the null literal. Remove this fix once the |
| 698 // corresponding analyzer bug is fixed: | 792 // corresponding analyzer bug is fixed: |
| 699 // https://code.google.com/p/dart/issues/detail?id=22854 | 793 // https://code.google.com/p/dart/issues/detail?id=22854 |
| 700 super.visitConditionalExpression(node); | 794 super.visitConditionalExpression(node); |
| 701 if (node.staticType.isDynamic) { | 795 if (node.staticType.isDynamic) { |
| 702 var thenExpr = node.thenExpression; | 796 var thenExpr = node.thenExpression; |
| 703 var elseExpr = node.elseExpression; | 797 var elseExpr = node.elseExpression; |
| 704 if (thenExpr.staticType.isBottom) { | 798 if (thenExpr.staticType.isBottom) { |
| 705 node.staticType = elseExpr.staticType; | 799 node.staticType = elseExpr.staticType; |
| 706 } else if (elseExpr.staticType.isBottom) { | 800 } else if (elseExpr.staticType.isBottom) { |
| 707 node.staticType = thenExpr.staticType; | 801 node.staticType = thenExpr.staticType; |
| 708 } | 802 } |
| 709 } | 803 } |
| 710 } | 804 } |
| 711 | 805 |
| 712 // Review note: no longer need to override visitFunctionExpression, this is | 806 // Review note: no longer need to override visitFunctionExpression, this is |
| 713 // handled by the analyzer internally. | 807 // handled by the analyzer internally. |
| 714 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? | 808 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? |
| 715 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression | 809 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression |
| 716 // type in a (...) => expr or just the written type? | 810 // type in a (...) => expr or just the written type? |
| 717 | 811 |
| 718 } | 812 } |
| OLD | NEW |