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. |