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..0c53dad08256ede52c81be4c971fb256a8573e4a 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,8 +259,8 @@ class InstanceMemberInferrer { |
// Then infer the types for the members. |
// |
classElement.fields.forEach(_inferField); |
- classElement.accessors.forEach(_inferAccessor); |
- classElement.methods.forEach(_inferMethod); |
+ classElement.accessors.forEach(_inferExecutable); |
+ classElement.methods.forEach(_inferExecutable); |
classElement.hasBeenInferred = true; |
} finally { |
elementsBeingInferred.remove(classElement); |
@@ -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 _inferExecutable(ExecutableElement element) { |
+ 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); |
} |
} |