| 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);
|
| }
|
| }
|
|
|
|
|