Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(382)

Side by Side Diff: pkg/analyzer/lib/src/generated/element_resolver.dart

Issue 1061043002: Remove union type support from analyzer. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/analyzer/lib/src/generated/element.dart ('k') | pkg/analyzer/lib/src/generated/engine.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 library engine.resolver.element_resolver; 5 library engine.resolver.element_resolver;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'ast.dart'; 9 import 'ast.dart';
10 import 'element.dart'; 10 import 'element.dart';
(...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after
632 } 632 }
633 } 633 }
634 // 634 //
635 // Then check for error conditions. 635 // Then check for error conditions.
636 // 636 //
637 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement); 637 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement);
638 bool generatedWithTypePropagation = false; 638 bool generatedWithTypePropagation = false;
639 if (_enableHints && errorCode == null && staticElement == null) { 639 if (_enableHints && errorCode == null && staticElement == null) {
640 // The method lookup may have failed because there were multiple 640 // The method lookup may have failed because there were multiple
641 // incompatible choices. In this case we don't want to generate a hint. 641 // incompatible choices. In this case we don't want to generate a hint.
642 if (propagatedElement == null && propagatedType is UnionType) {
643 // TODO(collinsn): an improvement here is to make the propagated type
644 // of the method call the union of the propagated types of all possible
645 // calls.
646 if (_lookupMethods(target, propagatedType, methodName.name).length >
647 1) {
648 return null;
649 }
650 }
651 errorCode = _checkForInvocationError(target, false, propagatedElement); 642 errorCode = _checkForInvocationError(target, false, propagatedElement);
652 if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) { 643 if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) {
653 ClassElement classElementContext = null; 644 ClassElement classElementContext = null;
654 if (target == null) { 645 if (target == null) {
655 classElementContext = _resolver.enclosingClass; 646 classElementContext = _resolver.enclosingClass;
656 } else { 647 } else {
657 DartType type = target.bestType; 648 DartType type = target.bestType;
658 if (type != null) { 649 if (type != null) {
659 if (type.element is ClassElement) { 650 if (type.element is ClassElement) {
660 classElementContext = type.element as ClassElement; 651 classElementContext = type.element as ClassElement;
(...skipping 1055 matching lines...) Expand 10 before | Expand all | Expand 10 after
1716 method = interfaceType.lookUpMethodInSuperclass( 1707 method = interfaceType.lookUpMethodInSuperclass(
1717 methodName, _definingLibrary); 1708 methodName, _definingLibrary);
1718 } else { 1709 } else {
1719 method = interfaceType.lookUpMethod(methodName, _definingLibrary); 1710 method = interfaceType.lookUpMethod(methodName, _definingLibrary);
1720 } 1711 }
1721 if (method != null) { 1712 if (method != null) {
1722 return method; 1713 return method;
1723 } 1714 }
1724 return _lookUpMethodInInterfaces( 1715 return _lookUpMethodInInterfaces(
1725 interfaceType, false, methodName, new HashSet<ClassElement>()); 1716 interfaceType, false, methodName, new HashSet<ClassElement>());
1726 } else if (type is UnionType) {
1727 // TODO (collinsn): I want [computeMergedExecutableElement] to be general
1728 // and work with functions, methods, constructors, and property accessors.
1729 // However, I won't be able to assume it returns [MethodElement] here
1730 // then.
1731 return _maybeMergeExecutableElements(
1732 _lookupMethods(target, type, methodName)) as MethodElement;
1733 } 1717 }
1734 return null; 1718 return null;
1735 } 1719 }
1736 1720
1737 /** 1721 /**
1738 * Look up the method with the given [methodName] in the interfaces 1722 * Look up the method with the given [methodName] in the interfaces
1739 * implemented by the given [targetType], either directly or indirectly. 1723 * implemented by the given [targetType], either directly or indirectly.
1740 * Return the element representing the method that was found, or `null` if 1724 * Return the element representing the method that was found, or `null` if
1741 * there is no method with the given name. The flag [includeTargetType] should 1725 * there is no method with the given name. The flag [includeTargetType] should
1742 * be `true` if the search should include the target type. The 1726 * be `true` if the search should include the target type. The
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1778 } 1762 }
1779 InterfaceType superclass = targetType.superclass; 1763 InterfaceType superclass = targetType.superclass;
1780 if (superclass == null) { 1764 if (superclass == null) {
1781 return null; 1765 return null;
1782 } 1766 }
1783 return _lookUpMethodInInterfaces( 1767 return _lookUpMethodInInterfaces(
1784 superclass, true, methodName, visitedInterfaces); 1768 superclass, true, methodName, visitedInterfaces);
1785 } 1769 }
1786 1770
1787 /** 1771 /**
1788 * Look up all methods with the given [methodName] that are defined on the
1789 * given union [type].
1790 */
1791 Set<ExecutableElement> _lookupMethods(
1792 Expression target, UnionType type, String methodName) {
1793 Set<ExecutableElement> methods = new HashSet<ExecutableElement>();
1794 bool allElementsHaveMethod = true;
1795 for (DartType t in type.elements) {
1796 MethodElement m = _lookUpMethod(target, t, methodName);
1797 if (m != null) {
1798 methods.add(m);
1799 } else {
1800 allElementsHaveMethod = false;
1801 }
1802 }
1803 // For strict union types we require that all types in the union define the
1804 // method.
1805 if (AnalysisEngine.instance.strictUnionTypes) {
1806 if (allElementsHaveMethod) {
1807 return methods;
1808 } else {
1809 return new Set<ExecutableElement>();
1810 }
1811 } else {
1812 return methods;
1813 }
1814 }
1815
1816 /**
1817 * Look up the setter with the given [setterName] in the given [type]. Return 1772 * Look up the setter with the given [setterName] in the given [type]. Return
1818 * the element representing the setter that was found, or `null` if there is 1773 * the element representing the setter that was found, or `null` if there is
1819 * no setter with the given name. The [target] is the target of the 1774 * no setter with the given name. The [target] is the target of the
1820 * invocation, or `null` if there is no target. 1775 * invocation, or `null` if there is no target.
1821 */ 1776 */
1822 PropertyAccessorElement _lookUpSetter( 1777 PropertyAccessorElement _lookUpSetter(
1823 Expression target, DartType type, String setterName) { 1778 Expression target, DartType type, String setterName) {
1824 type = _resolveTypeParameter(type); 1779 type = _resolveTypeParameter(type);
1825 if (type is InterfaceType) { 1780 if (type is InterfaceType) {
1826 InterfaceType interfaceType = type; 1781 InterfaceType interfaceType = type;
(...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after
2382 * Given an invocation of the form 'e.m(a1, ..., an)', resolve 'e.m' to the 2337 * Given an invocation of the form 'e.m(a1, ..., an)', resolve 'e.m' to the
2383 * element being invoked. If the returned element is a method, then the method 2338 * element being invoked. If the returned element is a method, then the method
2384 * will be invoked. If the returned element is a getter, the getter will be 2339 * will be invoked. If the returned element is a getter, the getter will be
2385 * invoked without arguments and the result of that invocation will then be 2340 * invoked without arguments and the result of that invocation will then be
2386 * invoked with the arguments. The [target] is the target of the invocation 2341 * invoked with the arguments. The [target] is the target of the invocation
2387 * ('e'). The [targetType] is the type of the target. The [methodName] is th 2342 * ('e'). The [targetType] is the type of the target. The [methodName] is th
2388 * name of the method being invoked ('m'). 2343 * name of the method being invoked ('m').
2389 */ 2344 */
2390 Element _resolveInvokedElementWithTarget( 2345 Element _resolveInvokedElementWithTarget(
2391 Expression target, DartType targetType, SimpleIdentifier methodName) { 2346 Expression target, DartType targetType, SimpleIdentifier methodName) {
2392 if (targetType is InterfaceType || targetType is UnionType) { 2347 if (targetType is InterfaceType) {
2393 Element element = _lookUpMethod(target, targetType, methodName.name); 2348 Element element = _lookUpMethod(target, targetType, methodName.name);
2394 if (element == null) { 2349 if (element == null) {
2395 // 2350 //
2396 // If there's no method, then it's possible that 'm' is a getter that 2351 // If there's no method, then it's possible that 'm' is a getter that
2397 // returns a function. 2352 // returns a function.
2398 // 2353 //
2399 // TODO (collinsn): need to add union type support here too, in the 2354 // TODO (collinsn): need to add union type support here too, in the
2400 // style of [lookUpMethod]. 2355 // style of [lookUpMethod].
2401 element = _lookUpGetter(target, targetType, methodName.name); 2356 element = _lookUpGetter(target, targetType, methodName.name);
2402 } 2357 }
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
2479 propertyName.staticElement = staticElement; 2434 propertyName.staticElement = staticElement;
2480 propertyName.propagatedElement = propagatedElement; 2435 propertyName.propagatedElement = propagatedElement;
2481 bool shouldReportMissingMember_static = 2436 bool shouldReportMissingMember_static =
2482 _shouldReportMissingMember(staticType, staticElement); 2437 _shouldReportMissingMember(staticType, staticElement);
2483 bool shouldReportMissingMember_propagated = 2438 bool shouldReportMissingMember_propagated =
2484 !shouldReportMissingMember_static && 2439 !shouldReportMissingMember_static &&
2485 _enableHints && 2440 _enableHints &&
2486 _shouldReportMissingMember(propagatedType, propagatedElement) && 2441 _shouldReportMissingMember(propagatedType, propagatedElement) &&
2487 !_memberFoundInSubclass( 2442 !_memberFoundInSubclass(
2488 propagatedType.element, propertyName.name, false, true); 2443 propagatedType.element, propertyName.name, false, true);
2489 // TODO(collinsn): add support for errors on union types by extending
2490 // [lookupGetter] and [lookupSetter] in analogy with the earlier
2491 // [lookupMethod] extensions.
2492 if (propagatedType is UnionType) {
2493 shouldReportMissingMember_propagated = false;
2494 }
2495 if (shouldReportMissingMember_static || 2444 if (shouldReportMissingMember_static ||
2496 shouldReportMissingMember_propagated) { 2445 shouldReportMissingMember_propagated) {
2497 DartType staticOrPropagatedType = 2446 DartType staticOrPropagatedType =
2498 shouldReportMissingMember_static ? staticType : propagatedType; 2447 shouldReportMissingMember_static ? staticType : propagatedType;
2499 Element staticOrPropagatedEnclosingElt = staticOrPropagatedType.element; 2448 Element staticOrPropagatedEnclosingElt = staticOrPropagatedType.element;
2500 bool isStaticProperty = _isStatic(staticOrPropagatedEnclosingElt); 2449 bool isStaticProperty = _isStatic(staticOrPropagatedEnclosingElt);
2501 DartType displayType = staticOrPropagatedType != null 2450 DartType displayType = staticOrPropagatedType != null
2502 ? staticOrPropagatedType 2451 ? staticOrPropagatedType
2503 : propagatedType != null ? propagatedType : staticType; 2452 : propagatedType != null ? propagatedType : staticType;
2504 // Special getter cases. 2453 // Special getter cases.
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
2713 if (!isConditional && expression is Identifier) { 2662 if (!isConditional && expression is Identifier) {
2714 Element staticElement = expression.staticElement; 2663 Element staticElement = expression.staticElement;
2715 if (staticElement is ClassElementImpl) { 2664 if (staticElement is ClassElementImpl) {
2716 return staticElement; 2665 return staticElement;
2717 } 2666 }
2718 } 2667 }
2719 return null; 2668 return null;
2720 } 2669 }
2721 2670
2722 /** 2671 /**
2723 * Helper function for `maybeMergeExecutableElements` that does the actual
2724 * merging. The [elementArrayToMerge] is the non-empty list of elements to
2725 * merge.
2726 */
2727 static ExecutableElement _computeMergedExecutableElement(
2728 List<ExecutableElement> elementArrayToMerge) {
2729 // Flatten methods structurally. Based on
2730 // [InheritanceManager.computeMergedExecutableElement] and
2731 // [InheritanceManager.createSyntheticExecutableElement].
2732 //
2733 // However, the approach we take here is much simpler, but expected to work
2734 // well in the common case. It degrades gracefully in the uncommon case,
2735 // by computing the type [dynamic] for the method, preventing any
2736 // hints from being generated (TODO: not done yet).
2737 //
2738 // The approach is: we require that each [ExecutableElement] has the
2739 // same shape: the same number of required, optional positional, and
2740 // optional named parameters, in the same positions, and with the named
2741 // parameters in the same order. We compute a type by unioning pointwise.
2742 ExecutableElement e_0 = elementArrayToMerge[0];
2743 List<ParameterElement> ps_0 = e_0.parameters;
2744 List<ParameterElementImpl> ps_out =
2745 new List<ParameterElementImpl>(ps_0.length);
2746 for (int j = 0; j < ps_out.length; j++) {
2747 ps_out[j] = new ParameterElementImpl(ps_0[j].name, 0);
2748 ps_out[j].synthetic = true;
2749 ps_out[j].type = ps_0[j].type;
2750 ps_out[j].parameterKind = ps_0[j].parameterKind;
2751 }
2752 DartType r_out = e_0.returnType;
2753 for (int i = 1; i < elementArrayToMerge.length; i++) {
2754 ExecutableElement e_i = elementArrayToMerge[i];
2755 r_out = UnionTypeImpl.union([r_out, e_i.returnType]);
2756 List<ParameterElement> ps_i = e_i.parameters;
2757 // Each function must have the same number of params.
2758 if (ps_0.length != ps_i.length) {
2759 return null;
2760 // TODO (collinsn): return an element representing [dynamic] here
2761 // instead.
2762 } else {
2763 // Each function must have the same kind of params, with the same names,
2764 // in the same order.
2765 for (int j = 0; j < ps_i.length; j++) {
2766 if (ps_0[j].parameterKind != ps_i[j].parameterKind ||
2767 !identical(ps_0[j].name, ps_i[j].name)) {
2768 return null;
2769 } else {
2770 // The output parameter type is the union of the input parameter
2771 // types.
2772 ps_out[j].type =
2773 UnionTypeImpl.union([ps_out[j].type, ps_i[j].type]);
2774 }
2775 }
2776 }
2777 }
2778 // TODO (collinsn): this code should work for functions and methods,
2779 // so we may want [FunctionElementImpl]
2780 // instead here in some cases?
2781 // And then there are constructors and property accessors.
2782 // Maybe the answer is to create a new subclass of [ExecutableElementImpl]
2783 // which is used for merged executable elements, in analogy with
2784 // [MultiplyInheritedMethodElementImpl] and
2785 // [MultiplyInheritedPropertyAcessorElementImpl].
2786 ExecutableElementImpl e_out = new MethodElementImpl(e_0.name, 0);
2787 e_out.synthetic = true;
2788 e_out.returnType = r_out;
2789 e_out.parameters = ps_out;
2790 e_out.type = new FunctionTypeImpl.con1(e_out);
2791 // Get NPE in [toString()] w/o this.
2792 e_out.enclosingElement = e_0.enclosingElement;
2793 return e_out;
2794 }
2795
2796 /**
2797 * Return `true` if the given [identifier] is the return type of a constructor 2672 * Return `true` if the given [identifier] is the return type of a constructor
2798 * declaration. 2673 * declaration.
2799 */ 2674 */
2800 static bool _isConstructorReturnType(SimpleIdentifier identifier) { 2675 static bool _isConstructorReturnType(SimpleIdentifier identifier) {
2801 AstNode parent = identifier.parent; 2676 AstNode parent = identifier.parent;
2802 if (parent is ConstructorDeclaration) { 2677 if (parent is ConstructorDeclaration) {
2803 return identical(parent.returnType, identifier); 2678 return identical(parent.returnType, identifier);
2804 } 2679 }
2805 return false; 2680 return false;
2806 } 2681 }
(...skipping 25 matching lines...) Expand all
2832 } 2707 }
2833 if (node is ConstructorFieldInitializer) { 2708 if (node is ConstructorFieldInitializer) {
2834 return false; 2709 return false;
2835 } 2710 }
2836 if (node is MethodDeclaration) { 2711 if (node is MethodDeclaration) {
2837 return !node.isStatic; 2712 return !node.isStatic;
2838 } 2713 }
2839 } 2714 }
2840 return false; 2715 return false;
2841 } 2716 }
2842
2843 /**
2844 * Return a method representing the merge of the given [elements]. The type of
2845 * the merged element is the component-wise union of the types of the given
2846 * elements. If not all input elements have the same shape then `null` is
2847 * returned.
2848 */
2849 static ExecutableElement _maybeMergeExecutableElements(
2850 Set<ExecutableElement> elements) {
2851 List<ExecutableElement> elementArrayToMerge = new List.from(elements);
2852 if (elementArrayToMerge.length == 0) {
2853 return null;
2854 } else if (elementArrayToMerge.length == 1) {
2855 // If all methods are equal, don't bother building a new one.
2856 return elementArrayToMerge[0];
2857 } else {
2858 return _computeMergedExecutableElement(elementArrayToMerge);
2859 }
2860 }
2861 } 2717 }
2862 2718
2863 /** 2719 /**
2864 * An identifier that can be used to look up names in the lexical scope when 2720 * An identifier that can be used to look up names in the lexical scope when
2865 * there is no identifier in the AST structure. There is no identifier in the 2721 * there is no identifier in the AST structure. There is no identifier in the
2866 * AST when the parser could not distinguish between a method invocation and an 2722 * AST when the parser could not distinguish between a method invocation and an
2867 * invocation of a top-level function imported with a prefix. 2723 * invocation of a top-level function imported with a prefix.
2868 */ 2724 */
2869 class SyntheticIdentifier extends Identifier { 2725 class SyntheticIdentifier extends Identifier {
2870 /** 2726 /**
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
2914 2770
2915 @override 2771 @override
2916 Element get staticElement => null; 2772 Element get staticElement => null;
2917 2773
2918 @override 2774 @override
2919 accept(AstVisitor visitor) => null; 2775 accept(AstVisitor visitor) => null;
2920 2776
2921 @override 2777 @override
2922 void visitChildren(AstVisitor visitor) {} 2778 void visitChildren(AstVisitor visitor) {}
2923 } 2779 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/element.dart ('k') | pkg/analyzer/lib/src/generated/engine.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698