Chromium Code Reviews| Index: pkg/analyzer/lib/src/generated/element.dart |
| diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart |
| index 6f8d8d2e935bb79c8340b1d49045b7d7df1bbd65..b93e920e8e23a8ffffbb097604e445dc26d4cb6f 100644 |
| --- a/pkg/analyzer/lib/src/generated/element.dart |
| +++ b/pkg/analyzer/lib/src/generated/element.dart |
| @@ -1993,8 +1993,9 @@ class ConstructorMember extends ExecutableMember implements ConstructorElement { |
| * Initialize a newly created element to represent a constructor, based on the |
| * [baseElement], defined by the [definingType]. |
| */ |
| - ConstructorMember(ConstructorElement baseElement, InterfaceType definingType) |
| - : super(baseElement, definingType); |
| + ConstructorMember(ConstructorElement baseElement, InterfaceType definingType, |
| + [FunctionType type]) |
|
Leaf
2015/12/05 00:50:40
Document what type is in the comment?
Jennifer Messerly
2015/12/07 17:46:58
Done.
|
| + : super(baseElement, definingType, type); |
| @override |
| ConstructorElement get baseElement => super.baseElement as ConstructorElement; |
| @@ -2082,10 +2083,7 @@ class ConstructorMember extends ExecutableMember implements ConstructorElement { |
| if (baseType == substitutedType) { |
| return constructor; |
| } |
| - // TODO(brianwilkerson) Consider caching the substituted type in the |
| - // instance. It would use more memory but speed up some operations. |
| - // We need to see how often the type is being re-computed. |
| - return new ConstructorMember(constructor, definingType); |
| + return new ConstructorMember(constructor, definingType, substitutedType); |
| } |
| } |
| @@ -3574,7 +3572,7 @@ class EmbeddedHtmlScriptElementImpl extends HtmlScriptElementImpl |
| * An element representing an executable object, including functions, methods, |
| * constructors, getters, and setters. |
| */ |
| -abstract class ExecutableElement implements TypeParameterizedElement { |
| +abstract class ExecutableElement implements FunctionTypedElement { |
| /** |
| * An empty list of executable elements. |
| */ |
| @@ -3650,24 +3648,6 @@ abstract class ExecutableElement implements TypeParameterizedElement { |
| * executable element. |
| */ |
| List<LocalVariableElement> get localVariables; |
| - |
| - /** |
| - * Return a list containing all of the parameters defined by this executable |
| - * element. |
| - */ |
| - List<ParameterElement> get parameters; |
| - |
| - /** |
| - * Return the return type defined by this executable element. If the element |
| - * model is fully populated, then the [returnType] will not be `null`, even |
| - * if no return type was explicitly specified. |
| - */ |
| - DartType get returnType; |
| - |
| - /** |
| - * Return the type of function defined by this executable element. |
| - */ |
| - FunctionType get type; |
| } |
| /** |
| @@ -3942,12 +3922,19 @@ abstract class ExecutableElementImpl extends ElementImpl |
| * type parameters are known. |
| */ |
| abstract class ExecutableMember extends Member implements ExecutableElement { |
| + @override |
| + final FunctionType type; |
| + |
| /** |
| * Initialize a newly created element to represent a constructor, based on the |
| * [baseElement], defined by the [definingType]. |
| */ |
| - ExecutableMember(ExecutableElement baseElement, InterfaceType definingType) |
| - : super(baseElement, definingType); |
| + ExecutableMember(ExecutableElement baseElement, InterfaceType definingType, |
| + [FunctionType type]) |
|
Leaf
2015/12/05 00:50:40
ditto?
Jennifer Messerly
2015/12/07 17:46:58
Done.
|
| + : type = type ?? |
| + baseElement.type.substitute2(definingType.typeArguments, |
| + TypeParameterTypeImpl.getTypes(definingType.typeParameters)), |
| + super(baseElement, definingType); |
| @override |
| ExecutableElement get baseElement => super.baseElement as ExecutableElement; |
| @@ -4000,26 +3987,10 @@ abstract class ExecutableMember extends Member implements ExecutableElement { |
| } |
| @override |
| - List<ParameterElement> get parameters { |
| - List<ParameterElement> baseParameters = baseElement.parameters; |
| - int parameterCount = baseParameters.length; |
| - if (parameterCount == 0) { |
| - return baseParameters; |
| - } |
| - List<ParameterElement> parameterizedParameters = |
| - new List<ParameterElement>(parameterCount); |
| - for (int i = 0; i < parameterCount; i++) { |
| - parameterizedParameters[i] = |
| - ParameterMember.from(baseParameters[i], definingType); |
| - } |
| - return parameterizedParameters; |
| - } |
| - |
| - @override |
| - DartType get returnType => substituteFor(baseElement.returnType); |
| + List<ParameterElement> get parameters => type.parameters; |
| @override |
| - FunctionType get type => substituteFor(baseElement.type); |
| + DartType get returnType => type.returnType; |
| @override |
| List<TypeParameterElement> get typeParameters => baseElement.typeParameters; |
| @@ -4263,14 +4234,16 @@ class FieldFormalParameterMember extends ParameterMember |
| * [baseElement], defined by the [definingType]. |
| */ |
| FieldFormalParameterMember( |
| - FieldFormalParameterElement baseElement, ParameterizedType definingType) |
| - : super(baseElement, definingType); |
| + FieldFormalParameterElement baseElement, ParameterizedType definingType, |
| + [DartType type]) |
|
Leaf
2015/12/05 00:50:41
also.
|
| + : super(baseElement, definingType, type); |
| @override |
| FieldElement get field { |
| FieldElement field = (baseElement as FieldFormalParameterElement).field; |
| if (field is FieldElement) { |
| - return FieldMember.from(field, definingType); |
| + return FieldMember.from( |
| + field, substituteFor(field.enclosingElement.type)); |
| } |
| return field; |
| } |
| @@ -4296,9 +4269,6 @@ class FieldMember extends VariableMember implements FieldElement { |
| FieldElement get baseElement => super.baseElement as FieldElement; |
| @override |
| - InterfaceType get definingType => super.definingType as InterfaceType; |
| - |
| - @override |
| ClassElement get enclosingElement => baseElement.enclosingElement; |
| @override |
| @@ -4331,7 +4301,7 @@ class FieldMember extends VariableMember implements FieldElement { |
| * field. Return the member that was created, or the base field if no member |
| * was created. |
| */ |
| - static FieldElement from(FieldElement field, InterfaceType definingType) { |
| + static FieldElement from(FieldElement field, ParameterizedType definingType) { |
| if (!_isChangedByTypeSubstitution(field, definingType)) { |
| return field; |
| } |
| @@ -4347,11 +4317,12 @@ class FieldMember extends VariableMember implements FieldElement { |
| * arguments from the defining type. |
| */ |
| static bool _isChangedByTypeSubstitution( |
| - FieldElement field, InterfaceType definingType) { |
| + FieldElement field, ParameterizedType definingType) { |
| List<DartType> argumentTypes = definingType.typeArguments; |
| if (field != null && argumentTypes.length != 0) { |
| DartType baseType = field.type; |
| - List<DartType> parameterTypes = definingType.element.type.typeArguments; |
| + List<DartType> parameterTypes = |
| + (definingType.element as dynamic).type.typeArguments; |
|
Leaf
2015/12/05 00:50:40
Lack of a common superclass? Maybe at least a comm
Jennifer Messerly
2015/12/07 17:46:58
yup, exactly. I actually have an idea for how to f
|
| if (baseType != null) { |
| DartType substitutedType = |
| baseType.substitute2(argumentTypes, parameterTypes); |
| @@ -4526,6 +4497,70 @@ class FunctionElementImpl extends ExecutableElementImpl |
| } |
| /** |
| + * An element of a generic function, where the type parameters are known. |
| + */ |
| +// TODO(jmesserly): the term "function member" is a bit weird, but it allows |
| +// a certain consistency. |
| +class FunctionMember extends ExecutableMember implements FunctionElement { |
| + /** |
| + * Initialize a newly created element to represent a constructor, based on the |
| + * [baseElement], defined by the [definingType]. |
|
Leaf
2015/12/05 00:50:40
Comment cut & pasted?
Jennifer Messerly
2015/12/07 17:46:58
Done.
Jennifer Messerly
2015/12/07 17:46:58
Done.
|
| + */ |
| + FunctionMember(FunctionElement baseElement, [DartType type]) |
| + : super(baseElement, null, type); |
| + |
| + @override |
| + FunctionElement get baseElement => super.baseElement as FunctionElement; |
| + |
| + @override |
| + Element get enclosingElement => baseElement.enclosingElement; |
| + |
| + @override |
| + bool get isEntryPoint => baseElement.isEntryPoint; |
| + |
| + @override |
| + SourceRange get visibleRange => baseElement.visibleRange; |
| + |
| + @override |
| + accept(ElementVisitor visitor) => visitor.visitFunctionElement(this); |
| + |
| + @override |
| + FunctionDeclaration computeNode() => baseElement.computeNode(); |
| + |
| + @override |
| + String toString() { |
| + StringBuffer buffer = new StringBuffer(); |
| + buffer.write(baseElement.displayName); |
| + (type as FunctionTypeImpl).appendTo(buffer); |
| + return buffer.toString(); |
| + } |
| + |
| + /** |
| + * If the given [method]'s type is different when any type parameters from the |
| + * defining type's declaration are replaced with the actual type arguments |
| + * from the [definingType], create a method member representing the given |
| + * method. Return the member that was created, or the base method if no member |
| + * was created. |
| + */ |
| + static MethodElement from( |
| + MethodElement method, ParameterizedType definingType) { |
| + if (method == null || definingType.typeArguments.length == 0) { |
| + return method; |
| + } |
| + FunctionType baseType = method.type; |
| + List<DartType> argumentTypes = definingType.typeArguments; |
| + List<DartType> parameterTypes = |
| + TypeParameterTypeImpl.getTypes(definingType.typeParameters); |
| + FunctionType substitutedType = |
| + baseType.substitute2(argumentTypes, parameterTypes); |
| + if (baseType == substitutedType) { |
| + return method; |
| + } |
| + return new MethodMember(method, definingType, substitutedType); |
| + } |
| +} |
| + |
| +/** |
| * The type of a function, method, constructor, getter, or setter. Function |
| * types come in three variations: |
| * |
| @@ -4670,7 +4705,7 @@ abstract class FunctionType implements ParameterizedType { |
| * A function type alias (`typedef`). |
| */ |
| abstract class FunctionTypeAliasElement |
| - implements TypeDefiningElement, TypeParameterizedElement { |
| + implements TypeDefiningElement, FunctionTypedElement { |
| /** |
| * An empty array of type alias elements. |
| */ |
| @@ -4684,19 +4719,6 @@ abstract class FunctionTypeAliasElement |
| CompilationUnitElement get enclosingElement; |
| /** |
| - * Return a list containing all of the parameters defined by this type alias. |
| - */ |
| - List<ParameterElement> get parameters; |
| - |
| - /** |
| - * Return the return type defined by this type alias. |
| - */ |
| - DartType get returnType; |
| - |
| - @override |
| - FunctionType get type; |
| - |
| - /** |
| * Return the resolved function type alias node that declares this element. |
| * |
| * This method is expensive, because resolved AST might be evicted from cache, |
| @@ -4854,6 +4876,31 @@ class FunctionTypeAliasElementImpl extends ElementImpl |
| } |
| /** |
| + * An element that has a [FunctionType] as its [type]. |
| + * |
| + * This also provides convenient access to the parameters and return type. |
| + */ |
| +abstract class FunctionTypedElement implements TypeParameterizedElement { |
| + /** |
| + * Return a list containing all of the parameters defined by this executable |
| + * element. |
| + */ |
| + List<ParameterElement> get parameters; |
| + |
| + /** |
| + * Return the return type defined by this element. If the element model is |
| + * fully populated, then the [returnType] will not be `null`, even |
| + * if no return type was explicitly specified. |
| + */ |
| + DartType get returnType; |
| + |
| + /** |
| + * Return the type of function defined by this element. |
| + */ |
| + FunctionType get type; |
| +} |
| + |
| +/** |
| * The type of a function, method, constructor, getter, or setter. |
| */ |
| class FunctionTypeImpl extends TypeImpl implements FunctionType { |
| @@ -4958,26 +5005,12 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType { |
| /** |
| * Return the base parameter elements of this function element. |
| */ |
| - List<ParameterElement> get baseParameters { |
| - Element element = this.element; |
| - if (element is ExecutableElement) { |
| - return element.parameters; |
| - } else { |
| - return (element as FunctionTypeAliasElement).parameters; |
| - } |
| - } |
| + List<ParameterElement> get baseParameters => element.parameters; |
| /** |
| * Return the return type defined by this function's element. |
| */ |
| - DartType get baseReturnType { |
| - Element element = this.element; |
| - if (element is ExecutableElement) { |
| - return element.returnType; |
| - } else { |
| - return (element as FunctionTypeAliasElement).returnType; |
| - } |
| - } |
| + DartType get baseReturnType => element.returnType; |
| @override |
| List<TypeParameterElement> get boundTypeParameters => _boundTypeParameters; |
| @@ -5054,6 +5087,9 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType { |
| } |
| @override |
| + FunctionTypedElement get element => super.element; |
| + |
| + @override |
| int get hashCode { |
| if (element == null) { |
| return 0; |
| @@ -5076,6 +5112,26 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType { |
| return code; |
| } |
| + /** |
| + * The type arguments that were used to instantiate this function type, if |
| + * any, otherwise this will return an empty list. |
| + * |
| + * Given a function type `f`: |
| + * |
| + * f == f.originalFunction.instantiate(f.instantiatedTypeArguments) |
| + * |
| + * Will always hold. |
| + */ |
| + List<DartType> get instantiatedTypeArguments { |
| + int typeParameterCount = element.type.boundTypeParameters.length; |
| + if (typeParameterCount == 0) { |
| + return DartType.EMPTY_LIST; |
| + } |
| + // The substituted types at the end should be our bound type parameters. |
| + int skipCount = typeArguments.length - typeParameterCount; |
| + return new List<DartType>.from(typeArguments.skip(skipCount)); |
| + } |
| + |
| @override |
| Map<String, DartType> get namedParameterTypes { |
| LinkedHashMap<String, DartType> namedParameterTypes = |
| @@ -5173,6 +5229,20 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType { |
| return types; |
| } |
| + /** |
| + * If this is an instantiation of a generic function type, this will get |
| + * the original function from which it was instantiated. |
| + * |
| + * Otherwise, this will return `this`. |
| + */ |
| + FunctionTypeImpl get originalFunction { |
| + if (element.type.boundTypeParameters.isEmpty) { |
| + return this; |
| + } |
| + return (element.type as FunctionTypeImpl).substitute2(typeArguments, |
| + TypeParameterTypeImpl.getTypes(typeParameters), prunedTypedefs); |
| + } |
| + |
| @override |
| List<ParameterElement> get parameters { |
| List<ParameterElement> baseParameters = this.baseParameters; |
| @@ -8498,6 +8568,7 @@ abstract class Member implements Element { |
| * Return the type that results from replacing the type parameters in the |
| * given [type] with the type arguments associated with this member. |
| */ |
| + @deprecated |
| DartType substituteFor(DartType type) { |
| if (type == null) { |
| return null; |
| @@ -8648,8 +8719,9 @@ class MethodMember extends ExecutableMember implements MethodElement { |
| * Initialize a newly created element to represent a constructor, based on the |
| * [baseElement], defined by the [definingType]. |
|
Leaf
2015/12/05 00:50:40
update comment.
Jennifer Messerly
2015/12/07 17:46:58
Done.
|
| */ |
| - MethodMember(MethodElement baseElement, InterfaceType definingType) |
| - : super(baseElement, definingType); |
| + MethodMember(MethodElement baseElement, InterfaceType definingType, |
| + [DartType type]) |
| + : super(baseElement, definingType, type); |
| @override |
| MethodElement get baseElement => super.baseElement as MethodElement; |
| @@ -8707,10 +8779,7 @@ class MethodMember extends ExecutableMember implements MethodElement { |
| if (baseType == substitutedType) { |
| return method; |
| } |
| - // TODO(brianwilkerson) Consider caching the substituted type in the |
| - // instance. It would use more memory but speed up some operations. |
| - // We need to see how often the type is being re-computed. |
| - return new MethodMember(method, definingType); |
| + return new MethodMember(method, definingType, substitutedType); |
| } |
| } |
| @@ -9440,8 +9509,9 @@ class ParameterMember extends VariableMember |
| * Initialize a newly created element to represent a constructor, based on the |
| * [baseElement], defined by the [definingType]. |
|
Leaf
2015/12/05 00:50:40
update comment. I think here and elsewhere there
Jennifer Messerly
2015/12/07 17:46:58
Done.
|
| */ |
| - ParameterMember(ParameterElement baseElement, ParameterizedType definingType) |
| - : super(baseElement, definingType); |
| + ParameterMember(ParameterElement baseElement, ParameterizedType definingType, |
| + [DartType type]) |
| + : super._(baseElement, definingType, type); |
| @override |
| ParameterElement get baseElement => super.baseElement as ParameterElement; |
| @@ -9463,18 +9533,11 @@ class ParameterMember extends VariableMember |
| @override |
| List<ParameterElement> get parameters { |
| - List<ParameterElement> baseParameters = baseElement.parameters; |
| - int parameterCount = baseParameters.length; |
| - if (parameterCount == 0) { |
| - return baseParameters; |
| + DartType type = this.type; |
| + if (type is FunctionType) { |
| + return type.parameters; |
| } |
| - List<ParameterElement> parameterizedParameters = |
| - new List<ParameterElement>(parameterCount); |
| - for (int i = 0; i < parameterCount; i++) { |
| - parameterizedParameters[i] = |
| - ParameterMember.from(baseParameters[i], definingType); |
| - } |
| - return parameterizedParameters; |
| + return ParameterElement.EMPTY_LIST; |
| } |
| @override |
| @@ -9483,6 +9546,8 @@ class ParameterMember extends VariableMember |
| @override |
| SourceRange get visibleRange => baseElement.visibleRange; |
| + // TODO(jmesserly): this equality is broken. It should consider the defining |
| + // type as well, otherwise we're dropping the substitution. |
| @override |
| bool operator ==(Object object) => |
| object is ParameterMember && baseElement == object.baseElement; |
| @@ -9549,8 +9614,9 @@ class ParameterMember extends VariableMember |
| // Check if parameter type depends on defining type type arguments. |
| // It is possible that we did not resolve field formal parameter yet, |
| // so skip this check for it. |
| - bool isFieldFormal = parameter is FieldFormalParameterElement; |
| - if (!isFieldFormal) { |
| + if (parameter is FieldFormalParameterElement) { |
| + return new FieldFormalParameterMember(parameter, definingType); |
| + } else { |
| DartType baseType = parameter.type; |
| List<DartType> argumentTypes = definingType.typeArguments; |
| List<DartType> parameterTypes = |
| @@ -9560,15 +9626,8 @@ class ParameterMember extends VariableMember |
| if (baseType == substitutedType) { |
| return parameter; |
| } |
| + return new ParameterMember(parameter, definingType, substitutedType); |
| } |
| - // TODO(brianwilkerson) Consider caching the substituted type in the |
| - // instance. It would use more memory but speed up some operations. |
| - // We need to see how often the type is being re-computed. |
| - if (isFieldFormal) { |
| - return new FieldFormalParameterMember( |
| - parameter as FieldFormalParameterElement, definingType); |
| - } |
| - return new ParameterMember(parameter, definingType); |
| } |
| } |
| @@ -11195,12 +11254,25 @@ abstract class VariableElementImpl extends ElementImpl |
| * type parameters are known. |
| */ |
| abstract class VariableMember extends Member implements VariableElement { |
| + @override |
| + final DartType type; |
| + |
| /** |
| * Initialize a newly created element to represent a constructor, based on the |
| * [baseElement], defined by the [definingType]. |
|
Leaf
2015/12/05 00:50:40
comment.
Jennifer Messerly
2015/12/07 17:46:58
Done.
|
| */ |
| - VariableMember(VariableElement baseElement, ParameterizedType definingType) |
| - : super(baseElement, definingType); |
| + VariableMember(VariableElement baseElement, ParameterizedType definingType, |
| + [DartType type]) |
| + : type = type ?? |
| + baseElement.type.substitute2(definingType.typeArguments, |
| + TypeParameterTypeImpl.getTypes(definingType.typeParameters)), |
| + super(baseElement, definingType); |
| + |
| + // TODO(jmesserly): this is temporary to allow the ParameterMember subclass. |
| + // Apparently mixins don't work with optional params. |
| + VariableMember._(VariableElement baseElement, ParameterizedType definingType, |
| + DartType type) |
| + : this(baseElement, definingType, type); |
| @override |
| VariableElement get baseElement => super.baseElement as VariableElement; |
| @@ -11239,9 +11311,6 @@ abstract class VariableMember extends Member implements VariableElement { |
| bool get isStatic => baseElement.isStatic; |
| @override |
| - DartType get type => substituteFor(baseElement.type); |
| - |
| - @override |
| void visitChildren(ElementVisitor visitor) { |
| // TODO(brianwilkerson) We need to finish implementing the accessors used |
| // below so that we can safely invoke them. |