| OLD | NEW |
| 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; | 5 library engine.resolver; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'ast.dart'; | 9 import 'ast.dart'; |
| 10 import 'constant.dart'; | 10 import 'constant.dart'; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 typedef ResolverVisitor ResolverVisitorFactory( | 37 typedef ResolverVisitor ResolverVisitorFactory( |
| 38 Library library, Source source, TypeProvider typeProvider); | 38 Library library, Source source, TypeProvider typeProvider); |
| 39 | 39 |
| 40 typedef StaticTypeAnalyzer StaticTypeAnalyzerFactory(ResolverVisitor visitor); | 40 typedef StaticTypeAnalyzer StaticTypeAnalyzerFactory(ResolverVisitor visitor); |
| 41 | 41 |
| 42 typedef TypeResolverVisitor TypeResolverVisitorFactory( | 42 typedef TypeResolverVisitor TypeResolverVisitorFactory( |
| 43 Library library, Source source, TypeProvider typeProvider); | 43 Library library, Source source, TypeProvider typeProvider); |
| 44 | 44 |
| 45 typedef void VoidFunction(); | 45 typedef void VoidFunction(); |
| 46 | 46 |
| 47 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); |
| 48 |
| 49 typedef bool _SubtypeChecker<T>(T t1, T t2); |
| 50 |
| 47 /** | 51 /** |
| 48 * Instances of the class `BestPracticesVerifier` traverse an AST structure look
ing for | 52 * Instances of the class `BestPracticesVerifier` traverse an AST structure look
ing for |
| 49 * violations of Dart best practices. | 53 * violations of Dart best practices. |
| 50 */ | 54 */ |
| 51 class BestPracticesVerifier extends RecursiveAstVisitor<Object> { | 55 class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
| 52 // static String _HASHCODE_GETTER_NAME = "hashCode"; | 56 // static String _HASHCODE_GETTER_NAME = "hashCode"; |
| 53 | 57 |
| 54 static String _NULL_TYPE_NAME = "Null"; | 58 static String _NULL_TYPE_NAME = "Null"; |
| 55 | 59 |
| 56 static String _TO_INT_METHOD_NAME = "toInt"; | 60 static String _TO_INT_METHOD_NAME = "toInt"; |
| (...skipping 2447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2504 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element); | 2508 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element); |
| 2505 interfaceType.typeArguments = typeArguments; | 2509 interfaceType.typeArguments = typeArguments; |
| 2506 element.type = interfaceType; | 2510 element.type = interfaceType; |
| 2507 List<ConstructorElement> constructors = holder.constructors; | 2511 List<ConstructorElement> constructors = holder.constructors; |
| 2508 if (constructors.length == 0) { | 2512 if (constructors.length == 0) { |
| 2509 // | 2513 // |
| 2510 // Create the default constructor. | 2514 // Create the default constructor. |
| 2511 // | 2515 // |
| 2512 constructors = _createDefaultConstructors(interfaceType); | 2516 constructors = _createDefaultConstructors(interfaceType); |
| 2513 } | 2517 } |
| 2518 _setDocRange(element, node); |
| 2514 element.abstract = node.isAbstract; | 2519 element.abstract = node.isAbstract; |
| 2515 element.accessors = holder.accessors; | 2520 element.accessors = holder.accessors; |
| 2516 element.constructors = constructors; | 2521 element.constructors = constructors; |
| 2517 element.fields = holder.fields; | 2522 element.fields = holder.fields; |
| 2518 element.methods = holder.methods; | 2523 element.methods = holder.methods; |
| 2519 element.typeParameters = typeParameters; | 2524 element.typeParameters = typeParameters; |
| 2520 element.validMixin = _isValidMixin; | 2525 element.validMixin = _isValidMixin; |
| 2521 int functionTypeCount = _functionTypesToFix.length; | 2526 int functionTypeCount = _functionTypesToFix.length; |
| 2522 for (int i = 0; i < functionTypeCount; i++) { | 2527 for (int i = 0; i < functionTypeCount; i++) { |
| 2523 _functionTypesToFix[i].typeArguments = typeArguments; | 2528 _functionTypesToFix[i].typeArguments = typeArguments; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2577 _inFunction = true; | 2582 _inFunction = true; |
| 2578 try { | 2583 try { |
| 2579 _visitChildren(holder, node); | 2584 _visitChildren(holder, node); |
| 2580 } finally { | 2585 } finally { |
| 2581 _inFunction = wasInFunction; | 2586 _inFunction = wasInFunction; |
| 2582 } | 2587 } |
| 2583 FunctionBody body = node.body; | 2588 FunctionBody body = node.body; |
| 2584 SimpleIdentifier constructorName = node.name; | 2589 SimpleIdentifier constructorName = node.name; |
| 2585 ConstructorElementImpl element = | 2590 ConstructorElementImpl element = |
| 2586 new ConstructorElementImpl.forNode(constructorName); | 2591 new ConstructorElementImpl.forNode(constructorName); |
| 2592 _setDocRange(element, node); |
| 2587 if (node.externalKeyword != null) { | 2593 if (node.externalKeyword != null) { |
| 2588 element.external = true; | 2594 element.external = true; |
| 2589 } | 2595 } |
| 2590 if (node.factoryKeyword != null) { | 2596 if (node.factoryKeyword != null) { |
| 2591 element.factory = true; | 2597 element.factory = true; |
| 2592 } | 2598 } |
| 2593 element.functions = holder.functions; | 2599 element.functions = holder.functions; |
| 2594 element.labels = holder.labels; | 2600 element.labels = holder.labels; |
| 2595 element.localVariables = holder.localVariables; | 2601 element.localVariables = holder.localVariables; |
| 2596 element.parameters = holder.parameters; | 2602 element.parameters = holder.parameters; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2681 normalParameter.accept(this); | 2687 normalParameter.accept(this); |
| 2682 holder.validate(); | 2688 holder.validate(); |
| 2683 return null; | 2689 return null; |
| 2684 } | 2690 } |
| 2685 | 2691 |
| 2686 @override | 2692 @override |
| 2687 Object visitEnumDeclaration(EnumDeclaration node) { | 2693 Object visitEnumDeclaration(EnumDeclaration node) { |
| 2688 SimpleIdentifier enumName = node.name; | 2694 SimpleIdentifier enumName = node.name; |
| 2689 ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName); | 2695 ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName); |
| 2690 enumElement.enum2 = true; | 2696 enumElement.enum2 = true; |
| 2697 _setDocRange(enumElement, node); |
| 2691 InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement); | 2698 InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement); |
| 2692 enumElement.type = enumType; | 2699 enumElement.type = enumType; |
| 2693 // The equivalent code for enums in the spec shows a single constructor, | 2700 // The equivalent code for enums in the spec shows a single constructor, |
| 2694 // but that constructor is not callable (since it is a compile-time error | 2701 // but that constructor is not callable (since it is a compile-time error |
| 2695 // to subclass, mix-in, implement, or explicitly instantiate an enum). So | 2702 // to subclass, mix-in, implement, or explicitly instantiate an enum). So |
| 2696 // we represent this as having no constructors. | 2703 // we represent this as having no constructors. |
| 2697 enumElement.constructors = ConstructorElement.EMPTY_LIST; | 2704 enumElement.constructors = ConstructorElement.EMPTY_LIST; |
| 2698 _currentHolder.addEnum(enumElement); | 2705 _currentHolder.addEnum(enumElement); |
| 2699 enumName.staticElement = enumElement; | 2706 enumName.staticElement = enumElement; |
| 2700 return super.visitEnumDeclaration(node); | 2707 return super.visitEnumDeclaration(node); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2753 _visitChildren(holder, node); | 2760 _visitChildren(holder, node); |
| 2754 } finally { | 2761 } finally { |
| 2755 _inFunction = wasInFunction; | 2762 _inFunction = wasInFunction; |
| 2756 } | 2763 } |
| 2757 FunctionBody body = expression.body; | 2764 FunctionBody body = expression.body; |
| 2758 sc.Token property = node.propertyKeyword; | 2765 sc.Token property = node.propertyKeyword; |
| 2759 if (property == null || _inFunction) { | 2766 if (property == null || _inFunction) { |
| 2760 SimpleIdentifier functionName = node.name; | 2767 SimpleIdentifier functionName = node.name; |
| 2761 FunctionElementImpl element = | 2768 FunctionElementImpl element = |
| 2762 new FunctionElementImpl.forNode(functionName); | 2769 new FunctionElementImpl.forNode(functionName); |
| 2770 _setDocRange(element, node); |
| 2763 if (node.externalKeyword != null) { | 2771 if (node.externalKeyword != null) { |
| 2764 element.external = true; | 2772 element.external = true; |
| 2765 } | 2773 } |
| 2766 element.functions = holder.functions; | 2774 element.functions = holder.functions; |
| 2767 element.labels = holder.labels; | 2775 element.labels = holder.labels; |
| 2768 element.localVariables = holder.localVariables; | 2776 element.localVariables = holder.localVariables; |
| 2769 element.parameters = holder.parameters; | 2777 element.parameters = holder.parameters; |
| 2770 element.typeParameters = holder.typeParameters; | 2778 element.typeParameters = holder.typeParameters; |
| 2771 if (body.isAsynchronous) { | 2779 if (body.isAsynchronous) { |
| 2772 element.asynchronous = true; | 2780 element.asynchronous = true; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2799 .getTopLevelVariable(propertyName) as TopLevelVariableElementImpl; | 2807 .getTopLevelVariable(propertyName) as TopLevelVariableElementImpl; |
| 2800 if (variable == null) { | 2808 if (variable == null) { |
| 2801 variable = new TopLevelVariableElementImpl(node.name.name, -1); | 2809 variable = new TopLevelVariableElementImpl(node.name.name, -1); |
| 2802 variable.final2 = true; | 2810 variable.final2 = true; |
| 2803 variable.synthetic = true; | 2811 variable.synthetic = true; |
| 2804 _currentHolder.addTopLevelVariable(variable); | 2812 _currentHolder.addTopLevelVariable(variable); |
| 2805 } | 2813 } |
| 2806 if (node.isGetter) { | 2814 if (node.isGetter) { |
| 2807 PropertyAccessorElementImpl getter = | 2815 PropertyAccessorElementImpl getter = |
| 2808 new PropertyAccessorElementImpl.forNode(propertyNameNode); | 2816 new PropertyAccessorElementImpl.forNode(propertyNameNode); |
| 2817 _setDocRange(getter, node); |
| 2809 if (node.externalKeyword != null) { | 2818 if (node.externalKeyword != null) { |
| 2810 getter.external = true; | 2819 getter.external = true; |
| 2811 } | 2820 } |
| 2812 getter.functions = holder.functions; | 2821 getter.functions = holder.functions; |
| 2813 getter.labels = holder.labels; | 2822 getter.labels = holder.labels; |
| 2814 getter.localVariables = holder.localVariables; | 2823 getter.localVariables = holder.localVariables; |
| 2815 if (body.isAsynchronous) { | 2824 if (body.isAsynchronous) { |
| 2816 getter.asynchronous = true; | 2825 getter.asynchronous = true; |
| 2817 } | 2826 } |
| 2818 if (body.isGenerator) { | 2827 if (body.isGenerator) { |
| 2819 getter.generator = true; | 2828 getter.generator = true; |
| 2820 } | 2829 } |
| 2821 getter.variable = variable; | 2830 getter.variable = variable; |
| 2822 getter.getter = true; | 2831 getter.getter = true; |
| 2823 getter.static = true; | 2832 getter.static = true; |
| 2824 variable.getter = getter; | 2833 variable.getter = getter; |
| 2825 if (node.returnType == null) { | 2834 if (node.returnType == null) { |
| 2826 getter.hasImplicitReturnType = true; | 2835 getter.hasImplicitReturnType = true; |
| 2827 } | 2836 } |
| 2828 _currentHolder.addAccessor(getter); | 2837 _currentHolder.addAccessor(getter); |
| 2829 expression.element = getter; | 2838 expression.element = getter; |
| 2830 propertyNameNode.staticElement = getter; | 2839 propertyNameNode.staticElement = getter; |
| 2831 } else { | 2840 } else { |
| 2832 PropertyAccessorElementImpl setter = | 2841 PropertyAccessorElementImpl setter = |
| 2833 new PropertyAccessorElementImpl.forNode(propertyNameNode); | 2842 new PropertyAccessorElementImpl.forNode(propertyNameNode); |
| 2843 _setDocRange(setter, node); |
| 2834 if (node.externalKeyword != null) { | 2844 if (node.externalKeyword != null) { |
| 2835 setter.external = true; | 2845 setter.external = true; |
| 2836 } | 2846 } |
| 2837 setter.functions = holder.functions; | 2847 setter.functions = holder.functions; |
| 2838 setter.labels = holder.labels; | 2848 setter.labels = holder.labels; |
| 2839 setter.localVariables = holder.localVariables; | 2849 setter.localVariables = holder.localVariables; |
| 2840 setter.parameters = holder.parameters; | 2850 setter.parameters = holder.parameters; |
| 2841 if (body.isAsynchronous) { | 2851 if (body.isAsynchronous) { |
| 2842 setter.asynchronous = true; | 2852 setter.asynchronous = true; |
| 2843 } | 2853 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2910 | 2920 |
| 2911 @override | 2921 @override |
| 2912 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | 2922 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 2913 ElementHolder holder = new ElementHolder(); | 2923 ElementHolder holder = new ElementHolder(); |
| 2914 _visitChildren(holder, node); | 2924 _visitChildren(holder, node); |
| 2915 SimpleIdentifier aliasName = node.name; | 2925 SimpleIdentifier aliasName = node.name; |
| 2916 List<ParameterElement> parameters = holder.parameters; | 2926 List<ParameterElement> parameters = holder.parameters; |
| 2917 List<TypeParameterElement> typeParameters = holder.typeParameters; | 2927 List<TypeParameterElement> typeParameters = holder.typeParameters; |
| 2918 FunctionTypeAliasElementImpl element = | 2928 FunctionTypeAliasElementImpl element = |
| 2919 new FunctionTypeAliasElementImpl.forNode(aliasName); | 2929 new FunctionTypeAliasElementImpl.forNode(aliasName); |
| 2930 _setDocRange(element, node); |
| 2920 element.parameters = parameters; | 2931 element.parameters = parameters; |
| 2921 element.typeParameters = typeParameters; | 2932 element.typeParameters = typeParameters; |
| 2922 FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(element); | 2933 FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(element); |
| 2923 type.typeArguments = _createTypeParameterTypes(typeParameters); | 2934 type.typeArguments = _createTypeParameterTypes(typeParameters); |
| 2924 element.type = type; | 2935 element.type = type; |
| 2925 _currentHolder.addTypeAlias(element); | 2936 _currentHolder.addTypeAlias(element); |
| 2926 aliasName.staticElement = element; | 2937 aliasName.staticElement = element; |
| 2927 holder.validate(); | 2938 holder.validate(); |
| 2928 return null; | 2939 return null; |
| 2929 } | 2940 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2981 FunctionBody body = node.body; | 2992 FunctionBody body = node.body; |
| 2982 if (property == null) { | 2993 if (property == null) { |
| 2983 SimpleIdentifier methodName = node.name; | 2994 SimpleIdentifier methodName = node.name; |
| 2984 String nameOfMethod = methodName.name; | 2995 String nameOfMethod = methodName.name; |
| 2985 if (nameOfMethod == sc.TokenType.MINUS.lexeme && | 2996 if (nameOfMethod == sc.TokenType.MINUS.lexeme && |
| 2986 node.parameters.parameters.length == 0) { | 2997 node.parameters.parameters.length == 0) { |
| 2987 nameOfMethod = "unary-"; | 2998 nameOfMethod = "unary-"; |
| 2988 } | 2999 } |
| 2989 MethodElementImpl element = | 3000 MethodElementImpl element = |
| 2990 new MethodElementImpl(nameOfMethod, methodName.offset); | 3001 new MethodElementImpl(nameOfMethod, methodName.offset); |
| 3002 _setDocRange(element, node); |
| 2991 element.abstract = node.isAbstract; | 3003 element.abstract = node.isAbstract; |
| 2992 if (node.externalKeyword != null) { | 3004 if (node.externalKeyword != null) { |
| 2993 element.external = true; | 3005 element.external = true; |
| 2994 } | 3006 } |
| 2995 element.functions = holder.functions; | 3007 element.functions = holder.functions; |
| 2996 element.labels = holder.labels; | 3008 element.labels = holder.labels; |
| 2997 element.localVariables = holder.localVariables; | 3009 element.localVariables = holder.localVariables; |
| 2998 element.parameters = holder.parameters; | 3010 element.parameters = holder.parameters; |
| 2999 element.static = isStatic; | 3011 element.static = isStatic; |
| 3000 element.typeParameters = holder.typeParameters; | 3012 element.typeParameters = holder.typeParameters; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3017 if (field == null) { | 3029 if (field == null) { |
| 3018 field = new FieldElementImpl(node.name.name, -1); | 3030 field = new FieldElementImpl(node.name.name, -1); |
| 3019 field.final2 = true; | 3031 field.final2 = true; |
| 3020 field.static = isStatic; | 3032 field.static = isStatic; |
| 3021 field.synthetic = true; | 3033 field.synthetic = true; |
| 3022 _currentHolder.addField(field); | 3034 _currentHolder.addField(field); |
| 3023 } | 3035 } |
| 3024 if (node.isGetter) { | 3036 if (node.isGetter) { |
| 3025 PropertyAccessorElementImpl getter = | 3037 PropertyAccessorElementImpl getter = |
| 3026 new PropertyAccessorElementImpl.forNode(propertyNameNode); | 3038 new PropertyAccessorElementImpl.forNode(propertyNameNode); |
| 3039 _setDocRange(getter, node); |
| 3027 if (node.externalKeyword != null) { | 3040 if (node.externalKeyword != null) { |
| 3028 getter.external = true; | 3041 getter.external = true; |
| 3029 } | 3042 } |
| 3030 getter.functions = holder.functions; | 3043 getter.functions = holder.functions; |
| 3031 getter.labels = holder.labels; | 3044 getter.labels = holder.labels; |
| 3032 getter.localVariables = holder.localVariables; | 3045 getter.localVariables = holder.localVariables; |
| 3033 if (body.isAsynchronous) { | 3046 if (body.isAsynchronous) { |
| 3034 getter.asynchronous = true; | 3047 getter.asynchronous = true; |
| 3035 } | 3048 } |
| 3036 if (body.isGenerator) { | 3049 if (body.isGenerator) { |
| 3037 getter.generator = true; | 3050 getter.generator = true; |
| 3038 } | 3051 } |
| 3039 getter.variable = field; | 3052 getter.variable = field; |
| 3040 getter.abstract = node.isAbstract; | 3053 getter.abstract = node.isAbstract; |
| 3041 getter.getter = true; | 3054 getter.getter = true; |
| 3042 getter.static = isStatic; | 3055 getter.static = isStatic; |
| 3043 field.getter = getter; | 3056 field.getter = getter; |
| 3044 if (node.returnType == null) { | 3057 if (node.returnType == null) { |
| 3045 getter.hasImplicitReturnType = true; | 3058 getter.hasImplicitReturnType = true; |
| 3046 } | 3059 } |
| 3047 _currentHolder.addAccessor(getter); | 3060 _currentHolder.addAccessor(getter); |
| 3048 propertyNameNode.staticElement = getter; | 3061 propertyNameNode.staticElement = getter; |
| 3049 } else { | 3062 } else { |
| 3050 PropertyAccessorElementImpl setter = | 3063 PropertyAccessorElementImpl setter = |
| 3051 new PropertyAccessorElementImpl.forNode(propertyNameNode); | 3064 new PropertyAccessorElementImpl.forNode(propertyNameNode); |
| 3065 _setDocRange(setter, node); |
| 3052 if (node.externalKeyword != null) { | 3066 if (node.externalKeyword != null) { |
| 3053 setter.external = true; | 3067 setter.external = true; |
| 3054 } | 3068 } |
| 3055 setter.functions = holder.functions; | 3069 setter.functions = holder.functions; |
| 3056 setter.labels = holder.labels; | 3070 setter.labels = holder.labels; |
| 3057 setter.localVariables = holder.localVariables; | 3071 setter.localVariables = holder.localVariables; |
| 3058 setter.parameters = holder.parameters; | 3072 setter.parameters = holder.parameters; |
| 3059 if (body.isAsynchronous) { | 3073 if (body.isAsynchronous) { |
| 3060 setter.asynchronous = true; | 3074 setter.asynchronous = true; |
| 3061 } | 3075 } |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3178 VariableElementImpl element; | 3192 VariableElementImpl element; |
| 3179 if (_inFieldContext) { | 3193 if (_inFieldContext) { |
| 3180 SimpleIdentifier fieldName = node.name; | 3194 SimpleIdentifier fieldName = node.name; |
| 3181 FieldElementImpl field; | 3195 FieldElementImpl field; |
| 3182 if ((isConst || isFinal) && hasInitializer) { | 3196 if ((isConst || isFinal) && hasInitializer) { |
| 3183 field = new ConstFieldElementImpl.forNode(fieldName); | 3197 field = new ConstFieldElementImpl.forNode(fieldName); |
| 3184 } else { | 3198 } else { |
| 3185 field = new FieldElementImpl.forNode(fieldName); | 3199 field = new FieldElementImpl.forNode(fieldName); |
| 3186 } | 3200 } |
| 3187 element = field; | 3201 element = field; |
| 3202 if (node.parent.parent is FieldDeclaration) { |
| 3203 _setDocRange(element, node.parent.parent); |
| 3204 } |
| 3188 if ((node.parent as VariableDeclarationList).type == null) { | 3205 if ((node.parent as VariableDeclarationList).type == null) { |
| 3189 field.hasImplicitType = true; | 3206 field.hasImplicitType = true; |
| 3190 } | 3207 } |
| 3191 _currentHolder.addField(field); | 3208 _currentHolder.addField(field); |
| 3192 fieldName.staticElement = field; | 3209 fieldName.staticElement = field; |
| 3193 } else if (_inFunction) { | 3210 } else if (_inFunction) { |
| 3194 SimpleIdentifier variableName = node.name; | 3211 SimpleIdentifier variableName = node.name; |
| 3195 LocalVariableElementImpl variable; | 3212 LocalVariableElementImpl variable; |
| 3196 if (isConst && hasInitializer) { | 3213 if (isConst && hasInitializer) { |
| 3197 variable = new ConstLocalVariableElementImpl.forNode(variableName); | 3214 variable = new ConstLocalVariableElementImpl.forNode(variableName); |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3343 return parent.body; | 3360 return parent.body; |
| 3344 } else if (parent is MethodDeclaration) { | 3361 } else if (parent is MethodDeclaration) { |
| 3345 return parent.body; | 3362 return parent.body; |
| 3346 } | 3363 } |
| 3347 parent = parent.parent; | 3364 parent = parent.parent; |
| 3348 } | 3365 } |
| 3349 return null; | 3366 return null; |
| 3350 } | 3367 } |
| 3351 | 3368 |
| 3352 /** | 3369 /** |
| 3370 * If the given [node] has a documentation comment, remember its range |
| 3371 * into the given [element]. |
| 3372 */ |
| 3373 void _setDocRange(ElementImpl element, AnnotatedNode node) { |
| 3374 Comment comment = node.documentationComment; |
| 3375 if (comment != null && comment.isDocumentation) { |
| 3376 element.setDocRange(comment.offset, comment.length); |
| 3377 } |
| 3378 } |
| 3379 |
| 3380 /** |
| 3353 * Sets the visible source range for formal parameter. | 3381 * Sets the visible source range for formal parameter. |
| 3354 */ | 3382 */ |
| 3355 void _setParameterVisibleRange( | 3383 void _setParameterVisibleRange( |
| 3356 FormalParameter node, ParameterElementImpl element) { | 3384 FormalParameter node, ParameterElementImpl element) { |
| 3357 FunctionBody body = _getFunctionBody(node); | 3385 FunctionBody body = _getFunctionBody(node); |
| 3358 if (body != null) { | 3386 if (body != null) { |
| 3359 element.setVisibleRange(body.offset, body.length); | 3387 element.setVisibleRange(body.offset, body.length); |
| 3360 } | 3388 } |
| 3361 } | 3389 } |
| 3362 | 3390 |
| (...skipping 9350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12713 } | 12741 } |
| 12714 } else if (statement is FunctionDeclarationStatement) { | 12742 } else if (statement is FunctionDeclarationStatement) { |
| 12715 FunctionDeclarationStatement fds = statement; | 12743 FunctionDeclarationStatement fds = statement; |
| 12716 scope.hide(fds.functionDeclaration.element); | 12744 scope.hide(fds.functionDeclaration.element); |
| 12717 } | 12745 } |
| 12718 } | 12746 } |
| 12719 } | 12747 } |
| 12720 } | 12748 } |
| 12721 | 12749 |
| 12722 /** | 12750 /** |
| 12751 * Implementation of [TypeSystem] using the strong mode rules. |
| 12752 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md |
| 12753 */ |
| 12754 class StrongTypeSystemImpl implements TypeSystem { |
| 12755 final _specTypeSystem = new TypeSystemImpl(); |
| 12756 |
| 12757 StrongTypeSystemImpl(); |
| 12758 |
| 12759 @override |
| 12760 DartType getLeastUpperBound( |
| 12761 TypeProvider typeProvider, DartType type1, DartType type2) { |
| 12762 // TODO(leafp): Implement a strong mode version of this. |
| 12763 return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2); |
| 12764 } |
| 12765 |
| 12766 // TODO(leafp): Document the rules in play here |
| 12767 @override |
| 12768 bool isAssignableTo(DartType fromType, DartType toType) { |
| 12769 // An actual subtype |
| 12770 if (isSubtypeOf(fromType, toType)) { |
| 12771 return true; |
| 12772 } |
| 12773 |
| 12774 // Don't allow implicit downcasts between function types |
| 12775 // and call method objects, as these will almost always fail. |
| 12776 if ((fromType is FunctionType && _getCallMethodType(toType) != null) || |
| 12777 (toType is FunctionType && _getCallMethodType(fromType) != null)) { |
| 12778 return false; |
| 12779 } |
| 12780 |
| 12781 // If the subtype relation goes the other way, allow the implicit downcast. |
| 12782 // TODO(leafp): Emit warnings and hints for these in some way. |
| 12783 // TODO(leafp): Consider adding a flag to disable these? Or just rely on |
| 12784 // --warnings-as-errors? |
| 12785 if (isSubtypeOf(toType, fromType) || |
| 12786 _specTypeSystem.isAssignableTo(toType, fromType)) { |
| 12787 // TODO(leafp): error if type is known to be exact (literal, |
| 12788 // instance creation). |
| 12789 // TODO(leafp): Warn on composite downcast. |
| 12790 // TODO(leafp): hint on object/dynamic downcast. |
| 12791 // TODO(leafp): Consider allowing assignment casts. |
| 12792 return true; |
| 12793 } |
| 12794 |
| 12795 return false; |
| 12796 } |
| 12797 |
| 12798 @override |
| 12799 bool isSubtypeOf(DartType leftType, DartType rightType) { |
| 12800 return _isSubtypeOf(leftType, rightType, null); |
| 12801 } |
| 12802 |
| 12803 FunctionType _getCallMethodType(DartType t) { |
| 12804 if (t is InterfaceType) { |
| 12805 ClassElement element = t.element; |
| 12806 InheritanceManager manager = new InheritanceManager(element.library); |
| 12807 FunctionType callType = manager.lookupMemberType(t, "call"); |
| 12808 return callType; |
| 12809 } |
| 12810 return null; |
| 12811 } |
| 12812 |
| 12813 // Given a type t, if t is an interface type with a call method |
| 12814 // defined, return the function type for the call method, otherwise |
| 12815 // return null. |
| 12816 _GuardedSubtypeChecker<DartType> _guard( |
| 12817 _GuardedSubtypeChecker<DartType> check) { |
| 12818 return (DartType t1, DartType t2, Set<Element> visited) { |
| 12819 Element element = t1.element; |
| 12820 if (visited == null) { |
| 12821 visited = new HashSet<Element>(); |
| 12822 } |
| 12823 if (element == null || !visited.add(element)) { |
| 12824 return false; |
| 12825 } |
| 12826 try { |
| 12827 return check(t1, t2, visited); |
| 12828 } finally { |
| 12829 visited.remove(element); |
| 12830 } |
| 12831 }; |
| 12832 } |
| 12833 |
| 12834 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { |
| 12835 return (t.isDynamic && dynamicIsBottom) || t.isBottom; |
| 12836 } |
| 12837 |
| 12838 // Guard against loops in the class hierarchy |
| 12839 /** |
| 12840 * Check that [f1] is a subtype of [f2]. |
| 12841 * [fuzzyArrows] indicates whether or not the f1 and f2 should be |
| 12842 * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated |
| 12843 * as bottom). |
| 12844 */ |
| 12845 bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2, |
| 12846 {bool fuzzyArrows: true}) { |
| 12847 final r1s = f1.normalParameterTypes; |
| 12848 final o1s = f1.optionalParameterTypes; |
| 12849 final n1s = f1.namedParameterTypes; |
| 12850 final r2s = f2.normalParameterTypes; |
| 12851 final o2s = f2.optionalParameterTypes; |
| 12852 final n2s = f2.namedParameterTypes; |
| 12853 final ret1 = f1.returnType; |
| 12854 final ret2 = f2.returnType; |
| 12855 |
| 12856 // A -> B <: C -> D if C <: A and |
| 12857 // either D is void or B <: D |
| 12858 if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) { |
| 12859 return false; |
| 12860 } |
| 12861 |
| 12862 // Reject if one has named and the other has optional |
| 12863 if (n1s.length > 0 && o2s.length > 0) { |
| 12864 return false; |
| 12865 } |
| 12866 if (n2s.length > 0 && o1s.length > 0) { |
| 12867 return false; |
| 12868 } |
| 12869 |
| 12870 // Rebind _isSubtypeOf for convenience |
| 12871 _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) => |
| 12872 _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows); |
| 12873 |
| 12874 // f2 has named parameters |
| 12875 if (n2s.length > 0) { |
| 12876 // Check that every named parameter in f2 has a match in f1 |
| 12877 for (String k2 in n2s.keys) { |
| 12878 if (!n1s.containsKey(k2)) { |
| 12879 return false; |
| 12880 } |
| 12881 if (!parameterSubtype(n2s[k2], n1s[k2])) { |
| 12882 return false; |
| 12883 } |
| 12884 } |
| 12885 } |
| 12886 // If we get here, we either have no named parameters, |
| 12887 // or else the named parameters match and we have no optional |
| 12888 // parameters |
| 12889 |
| 12890 // If f1 has more required parameters, reject |
| 12891 if (r1s.length > r2s.length) { |
| 12892 return false; |
| 12893 } |
| 12894 |
| 12895 // If f2 has more required + optional parameters, reject |
| 12896 if (r2s.length + o2s.length > r1s.length + o1s.length) { |
| 12897 return false; |
| 12898 } |
| 12899 |
| 12900 // The parameter lists must look like the following at this point |
| 12901 // where rrr is a region of required, and ooo is a region of optionals. |
| 12902 // f1: rrr ooo ooo ooo |
| 12903 // f2: rrr rrr ooo |
| 12904 int rr = r1s.length; // required in both |
| 12905 int or = r2s.length - r1s.length; // optional in f1, required in f2 |
| 12906 int oo = o2s.length; // optional in both |
| 12907 |
| 12908 for (int i = 0; i < rr; ++i) { |
| 12909 if (!parameterSubtype(r2s[i], r1s[i])) { |
| 12910 return false; |
| 12911 } |
| 12912 } |
| 12913 for (int i = 0, j = rr; i < or; ++i, ++j) { |
| 12914 if (!parameterSubtype(r2s[j], o1s[i])) { |
| 12915 return false; |
| 12916 } |
| 12917 } |
| 12918 for (int i = or, j = 0; i < oo; ++i, ++j) { |
| 12919 if (!parameterSubtype(o2s[j], o1s[i])) { |
| 12920 return false; |
| 12921 } |
| 12922 } |
| 12923 return true; |
| 12924 } |
| 12925 |
| 12926 bool _isInterfaceSubtypeOf( |
| 12927 InterfaceType i1, InterfaceType i2, Set<Element> visited) { |
| 12928 // Guard recursive calls |
| 12929 _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype = |
| 12930 _guard(_isInterfaceSubtypeOf); |
| 12931 |
| 12932 if (i1 == i2) { |
| 12933 return true; |
| 12934 } |
| 12935 |
| 12936 if (i1.element == i2.element) { |
| 12937 List<DartType> tArgs1 = i1.typeArguments; |
| 12938 List<DartType> tArgs2 = i2.typeArguments; |
| 12939 |
| 12940 assert(tArgs1.length == tArgs2.length); |
| 12941 |
| 12942 for (int i = 0; i < tArgs1.length; i++) { |
| 12943 DartType t1 = tArgs1[i]; |
| 12944 DartType t2 = tArgs2[i]; |
| 12945 if (!isSubtypeOf(t1, t2)) { |
| 12946 return false; |
| 12947 } |
| 12948 } |
| 12949 return true; |
| 12950 } |
| 12951 |
| 12952 if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) { |
| 12953 return true; |
| 12954 } |
| 12955 |
| 12956 if (i1.isObject) { |
| 12957 return false; |
| 12958 } |
| 12959 |
| 12960 if (guardedInterfaceSubtype(i1.superclass, i2, visited)) { |
| 12961 return true; |
| 12962 } |
| 12963 |
| 12964 for (final parent in i1.interfaces) { |
| 12965 if (guardedInterfaceSubtype(parent, i2, visited)) { |
| 12966 return true; |
| 12967 } |
| 12968 } |
| 12969 |
| 12970 for (final parent in i1.mixins) { |
| 12971 if (guardedInterfaceSubtype(parent, i2, visited)) { |
| 12972 return true; |
| 12973 } |
| 12974 } |
| 12975 |
| 12976 return false; |
| 12977 } |
| 12978 |
| 12979 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, |
| 12980 {bool dynamicIsBottom: false}) { |
| 12981 // Guard recursive calls |
| 12982 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf); |
| 12983 |
| 12984 if (t1 == t2) { |
| 12985 return true; |
| 12986 } |
| 12987 |
| 12988 // The types are void, dynamic, bottom, interface types, function types |
| 12989 // and type parameters. We proceed by eliminating these different classes |
| 12990 // from consideration. |
| 12991 |
| 12992 // Trivially true. |
| 12993 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || |
| 12994 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { |
| 12995 return true; |
| 12996 } |
| 12997 |
| 12998 // Trivially false. |
| 12999 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || |
| 13000 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { |
| 13001 return false; |
| 13002 } |
| 13003 |
| 13004 // S <: T where S is a type variable |
| 13005 // T is not dynamic or object (handled above) |
| 13006 // S != T (handled above) |
| 13007 // So only true if bound of S is S' and |
| 13008 // S' <: T |
| 13009 if (t1 is TypeParameterType) { |
| 13010 DartType bound = t1.element.bound; |
| 13011 if (bound == null) return false; |
| 13012 return guardedSubtype(bound, t2, visited); |
| 13013 } |
| 13014 |
| 13015 if (t2 is TypeParameterType) { |
| 13016 return false; |
| 13017 } |
| 13018 |
| 13019 if (t1.isVoid || t2.isVoid) { |
| 13020 return false; |
| 13021 } |
| 13022 |
| 13023 // We've eliminated void, dynamic, bottom, and type parameters. The only |
| 13024 // cases are the combinations of interface type and function type. |
| 13025 |
| 13026 // A function type can only subtype an interface type if |
| 13027 // the interface type is Function |
| 13028 if (t1 is FunctionType && t2 is InterfaceType) { |
| 13029 return t2.isDartCoreFunction; |
| 13030 } |
| 13031 |
| 13032 // An interface type can only subtype a function type if |
| 13033 // the interface type declares a call method with a type |
| 13034 // which is a super type of the function type. |
| 13035 if (t1 is InterfaceType && t2 is FunctionType) { |
| 13036 var callType = _getCallMethodType(t1); |
| 13037 return (callType != null) && _isFunctionSubtypeOf(callType, t2); |
| 13038 } |
| 13039 |
| 13040 // Two interface types |
| 13041 if (t1 is InterfaceType && t2 is InterfaceType) { |
| 13042 return _isInterfaceSubtypeOf(t1, t2, visited); |
| 13043 } |
| 13044 |
| 13045 return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType); |
| 13046 } |
| 13047 |
| 13048 // TODO(leafp): Document the rules in play here |
| 13049 bool _isTop(DartType t, {bool dynamicIsBottom: false}) { |
| 13050 return (t.isDynamic && !dynamicIsBottom) || t.isObject; |
| 13051 } |
| 13052 } |
| 13053 |
| 13054 /** |
| 12723 * Instances of this class manage the knowledge of what the set of subtypes are
for a given type. | 13055 * Instances of this class manage the knowledge of what the set of subtypes are
for a given type. |
| 12724 */ | 13056 */ |
| 12725 class SubtypeManager { | 13057 class SubtypeManager { |
| 12726 /** | 13058 /** |
| 12727 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype
s of the | 13059 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype
s of the |
| 12728 * key. | 13060 * key. |
| 12729 */ | 13061 */ |
| 12730 HashMap<ClassElement, HashSet<ClassElement>> _subtypeMap = | 13062 HashMap<ClassElement, HashSet<ClassElement>> _subtypeMap = |
| 12731 new HashMap<ClassElement, HashSet<ClassElement>>(); | 13063 new HashMap<ClassElement, HashSet<ClassElement>>(); |
| 12732 | 13064 |
| (...skipping 2213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14946 | 15278 |
| 14947 /** | 15279 /** |
| 14948 * The interface `TypeSystem` defines the behavior of an object representing | 15280 * The interface `TypeSystem` defines the behavior of an object representing |
| 14949 * the type system. This provides a common location to put methods that act on | 15281 * the type system. This provides a common location to put methods that act on |
| 14950 * types but may need access to more global data structures, and it paves the | 15282 * types but may need access to more global data structures, and it paves the |
| 14951 * way for a possible future where we may wish to make the type system | 15283 * way for a possible future where we may wish to make the type system |
| 14952 * pluggable. | 15284 * pluggable. |
| 14953 */ | 15285 */ |
| 14954 abstract class TypeSystem { | 15286 abstract class TypeSystem { |
| 14955 /** | 15287 /** |
| 14956 * Create either a strong mode or regular type system based on context. | |
| 14957 */ | |
| 14958 static TypeSystem create(AnalysisContext context) { | |
| 14959 return (context.analysisOptions.strongMode) | |
| 14960 ? new StrongTypeSystemImpl() | |
| 14961 : new TypeSystemImpl(); | |
| 14962 } | |
| 14963 | |
| 14964 /** | |
| 14965 * Compute the least upper bound of two types. | 15288 * Compute the least upper bound of two types. |
| 14966 */ | 15289 */ |
| 14967 DartType getLeastUpperBound( | 15290 DartType getLeastUpperBound( |
| 14968 TypeProvider typeProvider, DartType type1, DartType type2); | 15291 TypeProvider typeProvider, DartType type1, DartType type2); |
| 14969 | 15292 |
| 14970 /** | 15293 /** |
| 14971 * Return `true` if the [leftType] is assignable to the [rightType] (that is, | 15294 * Return `true` if the [leftType] is assignable to the [rightType] (that is, |
| 14972 * if leftType <==> rightType). | 15295 * if leftType <==> rightType). |
| 14973 */ | 15296 */ |
| 14974 bool isAssignableTo(DartType leftType, DartType rightType); | 15297 bool isAssignableTo(DartType leftType, DartType rightType); |
| 14975 | 15298 |
| 14976 /** | 15299 /** |
| 14977 * Return `true` if the [leftType] is a subtype of the [rightType] (that is, | 15300 * Return `true` if the [leftType] is a subtype of the [rightType] (that is, |
| 14978 * if leftType <: rightType). | 15301 * if leftType <: rightType). |
| 14979 */ | 15302 */ |
| 14980 bool isSubtypeOf(DartType leftType, DartType rightType); | 15303 bool isSubtypeOf(DartType leftType, DartType rightType); |
| 15304 |
| 15305 /** |
| 15306 * Create either a strong mode or regular type system based on context. |
| 15307 */ |
| 15308 static TypeSystem create(AnalysisContext context) { |
| 15309 return (context.analysisOptions.strongMode) |
| 15310 ? new StrongTypeSystemImpl() |
| 15311 : new TypeSystemImpl(); |
| 15312 } |
| 14981 } | 15313 } |
| 14982 | 15314 |
| 14983 /** | 15315 /** |
| 14984 * Implementation of [TypeSystem] using the rules in the Dart specification. | 15316 * Implementation of [TypeSystem] using the rules in the Dart specification. |
| 14985 */ | 15317 */ |
| 14986 class TypeSystemImpl implements TypeSystem { | 15318 class TypeSystemImpl implements TypeSystem { |
| 14987 TypeSystemImpl(); | 15319 TypeSystemImpl(); |
| 14988 | 15320 |
| 14989 @override | 15321 @override |
| 14990 DartType getLeastUpperBound( | 15322 DartType getLeastUpperBound( |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 15070 bool isAssignableTo(DartType leftType, DartType rightType) { | 15402 bool isAssignableTo(DartType leftType, DartType rightType) { |
| 15071 return leftType.isAssignableTo(rightType); | 15403 return leftType.isAssignableTo(rightType); |
| 15072 } | 15404 } |
| 15073 | 15405 |
| 15074 @override | 15406 @override |
| 15075 bool isSubtypeOf(DartType leftType, DartType rightType) { | 15407 bool isSubtypeOf(DartType leftType, DartType rightType) { |
| 15076 return leftType.isSubtypeOf(rightType); | 15408 return leftType.isSubtypeOf(rightType); |
| 15077 } | 15409 } |
| 15078 } | 15410 } |
| 15079 | 15411 |
| 15080 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); | |
| 15081 typedef bool _SubtypeChecker<T>(T t1, T t2); | |
| 15082 | |
| 15083 /** | |
| 15084 * Implementation of [TypeSystem] using the strong mode rules. | |
| 15085 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md | |
| 15086 */ | |
| 15087 class StrongTypeSystemImpl implements TypeSystem { | |
| 15088 StrongTypeSystemImpl(); | |
| 15089 | |
| 15090 final _specTypeSystem = new TypeSystemImpl(); | |
| 15091 | |
| 15092 @override | |
| 15093 DartType getLeastUpperBound( | |
| 15094 TypeProvider typeProvider, DartType type1, DartType type2) { | |
| 15095 // TODO(leafp): Implement a strong mode version of this. | |
| 15096 return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2); | |
| 15097 } | |
| 15098 | |
| 15099 // TODO(leafp): Document the rules in play here | |
| 15100 @override | |
| 15101 bool isAssignableTo(DartType fromType, DartType toType) { | |
| 15102 // An actual subtype | |
| 15103 if (isSubtypeOf(fromType, toType)) { | |
| 15104 return true; | |
| 15105 } | |
| 15106 | |
| 15107 // Don't allow implicit downcasts between function types | |
| 15108 // and call method objects, as these will almost always fail. | |
| 15109 if ((fromType is FunctionType && _getCallMethodType(toType) != null) || | |
| 15110 (toType is FunctionType && _getCallMethodType(fromType) != null)) { | |
| 15111 return false; | |
| 15112 } | |
| 15113 | |
| 15114 // If the subtype relation goes the other way, allow the implicit downcast. | |
| 15115 // TODO(leafp): Emit warnings and hints for these in some way. | |
| 15116 // TODO(leafp): Consider adding a flag to disable these? Or just rely on | |
| 15117 // --warnings-as-errors? | |
| 15118 if (isSubtypeOf(toType, fromType) || | |
| 15119 _specTypeSystem.isAssignableTo(toType, fromType)) { | |
| 15120 // TODO(leafp): error if type is known to be exact (literal, | |
| 15121 // instance creation). | |
| 15122 // TODO(leafp): Warn on composite downcast. | |
| 15123 // TODO(leafp): hint on object/dynamic downcast. | |
| 15124 // TODO(leafp): Consider allowing assignment casts. | |
| 15125 return true; | |
| 15126 } | |
| 15127 | |
| 15128 return false; | |
| 15129 } | |
| 15130 | |
| 15131 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { | |
| 15132 return (t.isDynamic && dynamicIsBottom) || t.isBottom; | |
| 15133 } | |
| 15134 | |
| 15135 bool _isTop(DartType t, {bool dynamicIsBottom: false}) { | |
| 15136 return (t.isDynamic && !dynamicIsBottom) || t.isObject; | |
| 15137 } | |
| 15138 | |
| 15139 // Given a type t, if t is an interface type with a call method | |
| 15140 // defined, return the function type for the call method, otherwise | |
| 15141 // return null. | |
| 15142 FunctionType _getCallMethodType(DartType t) { | |
| 15143 if (t is InterfaceType) { | |
| 15144 ClassElement element = t.element; | |
| 15145 InheritanceManager manager = new InheritanceManager(element.library); | |
| 15146 FunctionType callType = manager.lookupMemberType(t, "call"); | |
| 15147 return callType; | |
| 15148 } | |
| 15149 return null; | |
| 15150 } | |
| 15151 | |
| 15152 /** | |
| 15153 * Check that [f1] is a subtype of [f2]. | |
| 15154 * [fuzzyArrows] indicates whether or not the f1 and f2 should be | |
| 15155 * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated | |
| 15156 * as bottom). | |
| 15157 */ | |
| 15158 bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2, | |
| 15159 {bool fuzzyArrows: true}) { | |
| 15160 final r1s = f1.normalParameterTypes; | |
| 15161 final o1s = f1.optionalParameterTypes; | |
| 15162 final n1s = f1.namedParameterTypes; | |
| 15163 final r2s = f2.normalParameterTypes; | |
| 15164 final o2s = f2.optionalParameterTypes; | |
| 15165 final n2s = f2.namedParameterTypes; | |
| 15166 final ret1 = f1.returnType; | |
| 15167 final ret2 = f2.returnType; | |
| 15168 | |
| 15169 // A -> B <: C -> D if C <: A and | |
| 15170 // either D is void or B <: D | |
| 15171 if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) { | |
| 15172 return false; | |
| 15173 } | |
| 15174 | |
| 15175 // Reject if one has named and the other has optional | |
| 15176 if (n1s.length > 0 && o2s.length > 0) { | |
| 15177 return false; | |
| 15178 } | |
| 15179 if (n2s.length > 0 && o1s.length > 0) { | |
| 15180 return false; | |
| 15181 } | |
| 15182 | |
| 15183 // Rebind _isSubtypeOf for convenience | |
| 15184 _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) => | |
| 15185 _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows); | |
| 15186 | |
| 15187 // f2 has named parameters | |
| 15188 if (n2s.length > 0) { | |
| 15189 // Check that every named parameter in f2 has a match in f1 | |
| 15190 for (String k2 in n2s.keys) { | |
| 15191 if (!n1s.containsKey(k2)) { | |
| 15192 return false; | |
| 15193 } | |
| 15194 if (!parameterSubtype(n2s[k2], n1s[k2])) { | |
| 15195 return false; | |
| 15196 } | |
| 15197 } | |
| 15198 } | |
| 15199 // If we get here, we either have no named parameters, | |
| 15200 // or else the named parameters match and we have no optional | |
| 15201 // parameters | |
| 15202 | |
| 15203 // If f1 has more required parameters, reject | |
| 15204 if (r1s.length > r2s.length) { | |
| 15205 return false; | |
| 15206 } | |
| 15207 | |
| 15208 // If f2 has more required + optional parameters, reject | |
| 15209 if (r2s.length + o2s.length > r1s.length + o1s.length) { | |
| 15210 return false; | |
| 15211 } | |
| 15212 | |
| 15213 // The parameter lists must look like the following at this point | |
| 15214 // where rrr is a region of required, and ooo is a region of optionals. | |
| 15215 // f1: rrr ooo ooo ooo | |
| 15216 // f2: rrr rrr ooo | |
| 15217 int rr = r1s.length; // required in both | |
| 15218 int or = r2s.length - r1s.length; // optional in f1, required in f2 | |
| 15219 int oo = o2s.length; // optional in both | |
| 15220 | |
| 15221 for (int i = 0; i < rr; ++i) { | |
| 15222 if (!parameterSubtype(r2s[i], r1s[i])) { | |
| 15223 return false; | |
| 15224 } | |
| 15225 } | |
| 15226 for (int i = 0, j = rr; i < or; ++i, ++j) { | |
| 15227 if (!parameterSubtype(r2s[j], o1s[i])) { | |
| 15228 return false; | |
| 15229 } | |
| 15230 } | |
| 15231 for (int i = or, j = 0; i < oo; ++i, ++j) { | |
| 15232 if (!parameterSubtype(o2s[j], o1s[i])) { | |
| 15233 return false; | |
| 15234 } | |
| 15235 } | |
| 15236 return true; | |
| 15237 } | |
| 15238 | |
| 15239 // Guard against loops in the class hierarchy | |
| 15240 _GuardedSubtypeChecker<DartType> _guard( | |
| 15241 _GuardedSubtypeChecker<DartType> check) { | |
| 15242 return (DartType t1, DartType t2, Set<Element> visited) { | |
| 15243 Element element = t1.element; | |
| 15244 if (visited == null) { | |
| 15245 visited = new HashSet<Element>(); | |
| 15246 } | |
| 15247 if (element == null || !visited.add(element)) { | |
| 15248 return false; | |
| 15249 } | |
| 15250 try { | |
| 15251 return check(t1, t2, visited); | |
| 15252 } finally { | |
| 15253 visited.remove(element); | |
| 15254 } | |
| 15255 }; | |
| 15256 } | |
| 15257 | |
| 15258 bool _isInterfaceSubtypeOf( | |
| 15259 InterfaceType i1, InterfaceType i2, Set<Element> visited) { | |
| 15260 // Guard recursive calls | |
| 15261 _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype = | |
| 15262 _guard(_isInterfaceSubtypeOf); | |
| 15263 | |
| 15264 if (i1 == i2) { | |
| 15265 return true; | |
| 15266 } | |
| 15267 | |
| 15268 if (i1.element == i2.element) { | |
| 15269 List<DartType> tArgs1 = i1.typeArguments; | |
| 15270 List<DartType> tArgs2 = i2.typeArguments; | |
| 15271 | |
| 15272 assert(tArgs1.length == tArgs2.length); | |
| 15273 | |
| 15274 for (int i = 0; i < tArgs1.length; i++) { | |
| 15275 DartType t1 = tArgs1[i]; | |
| 15276 DartType t2 = tArgs2[i]; | |
| 15277 if (!isSubtypeOf(t1, t2)) { | |
| 15278 return false; | |
| 15279 } | |
| 15280 } | |
| 15281 return true; | |
| 15282 } | |
| 15283 | |
| 15284 if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) { | |
| 15285 return true; | |
| 15286 } | |
| 15287 | |
| 15288 if (i1.isObject) { | |
| 15289 return false; | |
| 15290 } | |
| 15291 | |
| 15292 if (guardedInterfaceSubtype(i1.superclass, i2, visited)) { | |
| 15293 return true; | |
| 15294 } | |
| 15295 | |
| 15296 for (final parent in i1.interfaces) { | |
| 15297 if (guardedInterfaceSubtype(parent, i2, visited)) { | |
| 15298 return true; | |
| 15299 } | |
| 15300 } | |
| 15301 | |
| 15302 for (final parent in i1.mixins) { | |
| 15303 if (guardedInterfaceSubtype(parent, i2, visited)) { | |
| 15304 return true; | |
| 15305 } | |
| 15306 } | |
| 15307 | |
| 15308 return false; | |
| 15309 } | |
| 15310 | |
| 15311 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, | |
| 15312 {bool dynamicIsBottom: false}) { | |
| 15313 // Guard recursive calls | |
| 15314 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf); | |
| 15315 | |
| 15316 if (t1 == t2) { | |
| 15317 return true; | |
| 15318 } | |
| 15319 | |
| 15320 // The types are void, dynamic, bottom, interface types, function types | |
| 15321 // and type parameters. We proceed by eliminating these different classes | |
| 15322 // from consideration. | |
| 15323 | |
| 15324 // Trivially true. | |
| 15325 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || | |
| 15326 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { | |
| 15327 return true; | |
| 15328 } | |
| 15329 | |
| 15330 // Trivially false. | |
| 15331 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || | |
| 15332 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { | |
| 15333 return false; | |
| 15334 } | |
| 15335 | |
| 15336 // S <: T where S is a type variable | |
| 15337 // T is not dynamic or object (handled above) | |
| 15338 // S != T (handled above) | |
| 15339 // So only true if bound of S is S' and | |
| 15340 // S' <: T | |
| 15341 if (t1 is TypeParameterType) { | |
| 15342 DartType bound = t1.element.bound; | |
| 15343 if (bound == null) return false; | |
| 15344 return guardedSubtype(bound, t2, visited); | |
| 15345 } | |
| 15346 | |
| 15347 if (t2 is TypeParameterType) { | |
| 15348 return false; | |
| 15349 } | |
| 15350 | |
| 15351 if (t1.isVoid || t2.isVoid) { | |
| 15352 return false; | |
| 15353 } | |
| 15354 | |
| 15355 // We've eliminated void, dynamic, bottom, and type parameters. The only | |
| 15356 // cases are the combinations of interface type and function type. | |
| 15357 | |
| 15358 // A function type can only subtype an interface type if | |
| 15359 // the interface type is Function | |
| 15360 if (t1 is FunctionType && t2 is InterfaceType) { | |
| 15361 return t2.isDartCoreFunction; | |
| 15362 } | |
| 15363 | |
| 15364 // An interface type can only subtype a function type if | |
| 15365 // the interface type declares a call method with a type | |
| 15366 // which is a super type of the function type. | |
| 15367 if (t1 is InterfaceType && t2 is FunctionType) { | |
| 15368 var callType = _getCallMethodType(t1); | |
| 15369 return (callType != null) && _isFunctionSubtypeOf(callType, t2); | |
| 15370 } | |
| 15371 | |
| 15372 // Two interface types | |
| 15373 if (t1 is InterfaceType && t2 is InterfaceType) { | |
| 15374 return _isInterfaceSubtypeOf(t1, t2, visited); | |
| 15375 } | |
| 15376 | |
| 15377 return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType); | |
| 15378 } | |
| 15379 | |
| 15380 // TODO(leafp): Document the rules in play here | |
| 15381 @override | |
| 15382 bool isSubtypeOf(DartType leftType, DartType rightType) { | |
| 15383 return _isSubtypeOf(leftType, rightType, null); | |
| 15384 } | |
| 15385 } | |
| 15386 | |
| 15387 /** | 15412 /** |
| 15388 * Instances of the class [UnusedLocalElementsVerifier] traverse an element | 15413 * Instances of the class [UnusedLocalElementsVerifier] traverse an element |
| 15389 * structure looking for cases of [HintCode.UNUSED_ELEMENT], | 15414 * structure looking for cases of [HintCode.UNUSED_ELEMENT], |
| 15390 * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc. | 15415 * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc. |
| 15391 */ | 15416 */ |
| 15392 class UnusedLocalElementsVerifier extends RecursiveElementVisitor { | 15417 class UnusedLocalElementsVerifier extends RecursiveElementVisitor { |
| 15393 /** | 15418 /** |
| 15394 * The error listener to which errors will be reported. | 15419 * The error listener to which errors will be reported. |
| 15395 */ | 15420 */ |
| 15396 final AnalysisErrorListener _errorListener; | 15421 final AnalysisErrorListener _errorListener; |
| (...skipping 549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 15946 nonFields.add(node); | 15971 nonFields.add(node); |
| 15947 return null; | 15972 return null; |
| 15948 } | 15973 } |
| 15949 | 15974 |
| 15950 @override | 15975 @override |
| 15951 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); | 15976 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); |
| 15952 | 15977 |
| 15953 @override | 15978 @override |
| 15954 Object visitWithClause(WithClause node) => null; | 15979 Object visitWithClause(WithClause node) => null; |
| 15955 } | 15980 } |
| OLD | NEW |