| 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 c3716adcc0b22c848270f28947239856ce1523e3..46b84e026c8f8437cc558a0d52a142e3429ea918 100644
|
| --- a/pkg/analyzer/lib/src/task/strong_mode.dart
|
| +++ b/pkg/analyzer/lib/src/task/strong_mode.dart
|
| @@ -6,8 +6,11 @@ library analyzer.src.task.strong_mode;
|
|
|
| import 'dart:collection';
|
|
|
| +import 'package:analyzer/dart/element/element.dart';
|
| +import 'package:analyzer/dart/element/type.dart';
|
| +import 'package:analyzer/src/dart/element/element.dart';
|
| +import 'package:analyzer/src/dart/element/type.dart';
|
| import 'package:analyzer/src/generated/ast.dart';
|
| -import 'package:analyzer/src/generated/element.dart';
|
| import 'package:analyzer/src/generated/resolver.dart'
|
| show TypeProvider, InheritanceManager;
|
| import 'package:analyzer/src/generated/type_system.dart';
|
| @@ -137,6 +140,14 @@ class InstanceMemberInferrer {
|
| }
|
|
|
| /**
|
| + * Return `true` if the list of [elements] contains only methods.
|
| + */
|
| + bool _allSameElementKind(
|
| + ExecutableElement element, List<ExecutableElement> elements) {
|
| + return elements.every((e) => e.kind == element.kind);
|
| + }
|
| +
|
| + /**
|
| * Compute the best type for the [parameter] at the given [index] that must be
|
| * compatible with the types of the corresponding parameters of the given
|
| * [overriddenMethods].
|
| @@ -213,7 +224,7 @@ class InstanceMemberInferrer {
|
| matchingParameter = methodParameters.lastWhere(
|
| (ParameterElement methodParameter) =>
|
| methodParameter.parameterKind == ParameterKind.NAMED &&
|
| - methodParameter.name == parameter.name,
|
| + methodParameter.name == parameter.name,
|
| orElse: () => null);
|
| } else {
|
| //
|
| @@ -278,51 +289,10 @@ class InstanceMemberInferrer {
|
| }
|
| }
|
|
|
| - /**
|
| - * If the given [fieldElement] represents a non-synthetic instance field for
|
| - * which no type was provided, infer the type of the field.
|
| - */
|
| - void _inferField(FieldElement fieldElement) {
|
| - if (!fieldElement.isSynthetic &&
|
| - !fieldElement.isStatic &&
|
| - fieldElement.hasImplicitType) {
|
| - //
|
| - // First look for overridden getters with the same name as the field.
|
| - //
|
| - List<ExecutableElement> overriddenGetters = inheritanceManager
|
| - .lookupOverrides(fieldElement.enclosingElement, fieldElement.name);
|
| - DartType newType = null;
|
| - if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) {
|
| - newType = _computeReturnType(overriddenGetters);
|
| - List<ExecutableElement> overriddenSetters = inheritanceManager
|
| - .lookupOverrides(
|
| - fieldElement.enclosingElement, fieldElement.name + '=');
|
| - if (!_isCompatible(newType, overriddenSetters)) {
|
| - newType = null;
|
| - }
|
| - }
|
| - //
|
| - // If there is no overridden getter or if the overridden getter's type is
|
| - // dynamic, then we can infer the type from the initialization expression
|
| - // without breaking subtype rules. We could potentially infer a consistent
|
| - // return type even if the overridden getter's type was not dynamic, but
|
| - // choose not to for simplicity. The field is required to be final to
|
| - // prevent choosing a type that is inconsistent with assignments we cannot
|
| - // analyze.
|
| - //
|
| - if (newType == null || newType.isDynamic) {
|
| - if (fieldElement.initializer != null &&
|
| - (fieldElement.isFinal || overriddenGetters.isEmpty)) {
|
| - newType = fieldElement.initializer.returnType;
|
| - }
|
| - }
|
| - if (newType == null || newType.isBottom) {
|
| - newType = typeProvider.dynamicType;
|
| - }
|
| - (fieldElement as FieldElementImpl).type = newType;
|
| - setReturnType(fieldElement.getter, newType);
|
| - if (!fieldElement.isFinal && !fieldElement.isConst) {
|
| - setParameterType(fieldElement.setter, newType);
|
| + void _inferConstructorFieldFormals(ConstructorElement element) {
|
| + for (ParameterElement p in element.parameters) {
|
| + if (p is FieldFormalParameterElement) {
|
| + _inferFieldFormalParameter(p);
|
| }
|
| }
|
| }
|
| @@ -377,29 +347,58 @@ class InstanceMemberInferrer {
|
| }
|
|
|
| /**
|
| - * 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.
|
| + * If the given [fieldElement] represents a non-synthetic instance field for
|
| + * which no type was provided, infer the type of the field.
|
| */
|
| - 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;
|
| + void _inferField(FieldElement fieldElement) {
|
| + if (!fieldElement.isSynthetic &&
|
| + !fieldElement.isStatic &&
|
| + fieldElement.hasImplicitType) {
|
| + //
|
| + // First look for overridden getters with the same name as the field.
|
| + //
|
| + List<ExecutableElement> overriddenGetters = inheritanceManager
|
| + .lookupOverrides(fieldElement.enclosingElement, fieldElement.name);
|
| + DartType newType = null;
|
| + if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) {
|
| + newType = _computeReturnType(overriddenGetters);
|
| + List<ExecutableElement> overriddenSetters =
|
| + inheritanceManager.lookupOverrides(
|
| + fieldElement.enclosingElement, fieldElement.name + '=');
|
| + if (!_isCompatible(newType, overriddenSetters)) {
|
| + newType = null;
|
| + }
|
| + }
|
| + //
|
| + // If there is no overridden getter or if the overridden getter's type is
|
| + // dynamic, then we can infer the type from the initialization expression
|
| + // without breaking subtype rules. We could potentially infer a consistent
|
| + // return type even if the overridden getter's type was not dynamic, but
|
| + // choose not to for simplicity. The field is required to be final to
|
| + // prevent choosing a type that is inconsistent with assignments we cannot
|
| + // analyze.
|
| + //
|
| + if (newType == null || newType.isDynamic) {
|
| + if (fieldElement.initializer != null &&
|
| + (fieldElement.isFinal || overriddenGetters.isEmpty)) {
|
| + newType = fieldElement.initializer.returnType;
|
| + }
|
| + }
|
| + if (newType == null || newType.isBottom) {
|
| + newType = typeProvider.dynamicType;
|
| + }
|
| + (fieldElement as FieldElementImpl).type = newType;
|
| + setReturnType(fieldElement.getter, newType);
|
| + if (!fieldElement.isFinal && !fieldElement.isConst) {
|
| + setParameterType(fieldElement.setter, newType);
|
| + }
|
| }
|
| - if (newType != null) {
|
| - (element.variable as VariableElementImpl).type = newType;
|
| + }
|
| +
|
| + void _inferFieldFormalParameter(FieldFormalParameterElement element) {
|
| + FieldElement field = element.field;
|
| + if (field != null && element.hasImplicitType) {
|
| + (element as FieldFormalParameterElementImpl).type = field.type;
|
| }
|
| }
|
|
|
| @@ -443,25 +442,29 @@ class InstanceMemberInferrer {
|
| }
|
|
|
| /**
|
| - * Return `true` if the list of [elements] contains only methods.
|
| + * 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.
|
| */
|
| - bool _allSameElementKind(
|
| - ExecutableElement element, List<ExecutableElement> elements) {
|
| - return elements.every((e) => e.kind == element.kind);
|
| - }
|
| -
|
| - void _inferConstructorFieldFormals(ConstructorElement element) {
|
| - for (ParameterElement p in element.parameters) {
|
| - if (p is FieldFormalParameterElement) {
|
| - _inferFieldFormalParameter(p);
|
| - }
|
| + void _updateSyntheticVariableType(PropertyAccessorElement element) {
|
| + assert(!element.isSynthetic);
|
| + PropertyAccessorElement getter = element;
|
| + if (element.isSetter) {
|
| + // See if we can find any getter.
|
| + getter = element.correspondingGetter;
|
| }
|
| - }
|
| -
|
| - void _inferFieldFormalParameter(FieldFormalParameterElement element) {
|
| - FieldElement field = element.field;
|
| - if (field != null && element.hasImplicitType) {
|
| - (element as FieldFormalParameterElementImpl).type = field.type;
|
| + 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;
|
| }
|
| }
|
| }
|
|
|