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 |