Chromium Code Reviews| Index: pkg/analyzer/lib/src/task/strong_mode.dart |
| diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart |
| index 2db99146898cde14482ece9d4e9880abd07112df..569693967fe2cb8b1c2ae24a32f222f42155b880 100644 |
| --- a/pkg/analyzer/lib/src/task/strong_mode.dart |
| +++ b/pkg/analyzer/lib/src/task/strong_mode.dart |
| @@ -231,37 +231,6 @@ class InstanceMemberInferrer { |
| } |
| /** |
| - * If the given [accessorElement] represents a non-synthetic instance getter |
| - * for which no return type was provided, infer the return type of the getter. |
| - */ |
| - void _inferAccessor(PropertyAccessorElement accessorElement) { |
| - if (!accessorElement.isSynthetic && |
| - accessorElement.isGetter && |
| - !accessorElement.isStatic && |
| - accessorElement.hasImplicitReturnType) { |
| - List<ExecutableElement> overriddenGetters = inheritanceManager |
| - .lookupOverrides( |
| - accessorElement.enclosingElement, accessorElement.name); |
| - if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) { |
| - DartType newType = _computeReturnType(overriddenGetters); |
| - List<ExecutableElement> overriddenSetters = inheritanceManager |
| - .lookupOverrides( |
| - accessorElement.enclosingElement, accessorElement.name + '='); |
| - PropertyAccessorElement setter = (accessorElement.enclosingElement |
| - as ClassElement).getSetter(accessorElement.name); |
| - if (setter != null) { |
| - overriddenSetters.add(setter); |
| - } |
| - if (!_isCompatible(newType, overriddenSetters)) { |
| - newType = typeProvider.dynamicType; |
| - } |
| - setReturnType(accessorElement, newType); |
| - (accessorElement.variable as FieldElementImpl).type = newType; |
| - } |
| - } |
| - } |
| - |
| - /** |
| * Infer type information for all of the instance members in the given |
| * [classElement]. |
| */ |
| @@ -290,7 +259,7 @@ class InstanceMemberInferrer { |
| // Then infer the types for the members. |
| // |
| classElement.fields.forEach(_inferField); |
| - classElement.accessors.forEach(_inferAccessor); |
| + classElement.accessors.forEach(_inferMethod); |
| classElement.methods.forEach(_inferMethod); |
| classElement.hasBeenInferred = true; |
| } finally { |
| @@ -344,47 +313,82 @@ class InstanceMemberInferrer { |
| } |
| /** |
| - * If the given [methodElement] represents a non-synthetic instance method |
| - * for which no return type was provided, infer the return type of the method. |
| + * If the given [element] represents a non-synthetic instance method, |
| + * getter or setter, infer the return type and any parameter type(s) where |
| + * they were not provided. |
| */ |
| - void _inferMethod(MethodElement methodElement) { |
| - if (methodElement.isSynthetic || methodElement.isStatic) { |
| + void _inferMethod(ExecutableElement element) { |
|
Brian Wilkerson
2015/09/24 19:31:51
nit: consider renaming to something more generic,
Jennifer Messerly
2015/09/24 20:20:43
good idea! done.
|
| + if (element.isSynthetic || element.isStatic) { |
| return; |
| } |
| List<ExecutableElement> overriddenMethods = null; |
| // |
| // Infer the return type. |
| // |
| - if (methodElement.hasImplicitReturnType) { |
| + if (element.hasImplicitReturnType) { |
| overriddenMethods = inheritanceManager.lookupOverrides( |
| - methodElement.enclosingElement, methodElement.name); |
| - if (overriddenMethods.isEmpty || !_onlyMethods(overriddenMethods)) { |
| + element.enclosingElement, element.name); |
| + if (overriddenMethods.isEmpty || |
| + !_allSameElementKind(element, overriddenMethods)) { |
| return; |
| } |
| - MethodElementImpl element = methodElement as MethodElementImpl; |
| setReturnType(element, _computeReturnType(overriddenMethods)); |
| + if (element is PropertyAccessorElement) { |
| + _updateSyntheticVariableType(element); |
| + } |
| } |
| // |
| // Infer the parameter types. |
| // |
| - List<ParameterElement> parameters = methodElement.parameters; |
| + List<ParameterElement> parameters = element.parameters; |
| int length = parameters.length; |
| for (int i = 0; i < length; ++i) { |
| ParameterElement parameter = parameters[i]; |
| if (parameter is ParameterElementImpl && parameter.hasImplicitType) { |
| if (overriddenMethods == null) { |
| overriddenMethods = inheritanceManager.lookupOverrides( |
| - methodElement.enclosingElement, methodElement.name); |
| + element.enclosingElement, element.name); |
| } |
| - if (overriddenMethods.isEmpty || !_onlyMethods(overriddenMethods)) { |
| + if (overriddenMethods.isEmpty || |
| + !_allSameElementKind(element, overriddenMethods)) { |
| return; |
| } |
| parameter.type = _computeParameterType(parameter, i, overriddenMethods); |
| + if (element is PropertyAccessorElement) { |
| + _updateSyntheticVariableType(element); |
| + } |
| } |
| } |
| } |
| /** |
| + * If the given [element] is a non-synthetic getter or setter, update its |
| + * synthetic variable's type to match the getter's return type, or if no |
| + * corresponding getter exists, use the setter's parameter type. |
| + * |
| + * In general, the type of the synthetic variable should not be used, because |
| + * getters and setters are independent methods. But this logic matches what |
| + * `TypeResolverVisitor.visitMethodDeclaration` would fill in there. |
| + */ |
| + void _updateSyntheticVariableType(PropertyAccessorElement element) { |
| + assert(!element.isSynthetic); |
| + PropertyAccessorElement getter = element; |
| + if (element.isSetter) { |
| + // See if we can find any getter. |
| + getter = element.correspondingGetter; |
| + } |
| + DartType newType; |
| + if (getter != null) { |
| + newType = getter.returnType; |
| + } else if (element.isSetter && element.parameters.isNotEmpty) { |
| + newType = element.parameters[0].type; |
| + } |
| + if (newType != null) { |
| + (element.variable as VariableElementImpl).type = newType; |
| + } |
| + } |
| + |
| + /** |
| * Infer type information for all of the instance members in the given |
| * interface [type]. |
| */ |
| @@ -426,13 +430,9 @@ class InstanceMemberInferrer { |
| /** |
| * Return `true` if the list of [elements] contains only methods. |
| */ |
| - bool _onlyMethods(List<ExecutableElement> elements) { |
| - for (ExecutableElement element in elements) { |
| - if (element is! MethodElement) { |
| - return false; |
| - } |
| - } |
| - return true; |
| + bool _allSameElementKind( |
| + ExecutableElement element, List<ExecutableElement> elements) { |
| + return elements.every((e) => e.kind == element.kind); |
| } |
| } |