Skip to content

Commit

Permalink
Update the element model to support extension methods
Browse files Browse the repository at this point in the history
Change-Id: Ia3bd6a19514368b3e046fead2eed0a4d0bfb133d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/108504
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
  • Loading branch information
bwilkerson authored and commit-bot@chromium.org committed Jul 11, 2019
1 parent a8331cd commit 97587b5
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 120 deletions.
24 changes: 12 additions & 12 deletions pkg/analyzer/lib/dart/element/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -349,9 +349,8 @@ abstract class ClassElement
///
/// Clients may not extend, implement or mix-in this class.
abstract class ClassMemberElement implements Element {
@override
ClassElement get enclosingElement;

// TODO(brianwilkerson) Either remove this class or rename it to something
// more correct, such as PotentiallyStaticElement.
/// Return `true` if this element is a static element. A static element is an
/// element that is not associated with a particular instance, but rather with
/// an entire library or class.
Expand Down Expand Up @@ -425,6 +424,9 @@ abstract class CompilationUnitElement implements Element, UriReferencedElement {
/// Clients may not extend, implement or mix-in this class.
abstract class ConstructorElement
implements ClassMemberElement, ExecutableElement, ConstantEvaluationTarget {
@override
ClassElement get enclosingElement;

/// Return `true` if this constructor is a const constructor.
bool get isConst;

Expand Down Expand Up @@ -1058,7 +1060,7 @@ abstract class ExportElement implements Element, UriReferencedElement {
/// An element that represents an extension.
///
/// Clients may not extend, implement or mix-in this class.
abstract class ExtensionElement implements Element {
abstract class ExtensionElement implements TypeParameterizedElement {
/// Return a list containing all of the accessors (getters and setters)
/// declared in this extension.
List<PropertyAccessorElement> get accessors;
Expand All @@ -1069,10 +1071,6 @@ abstract class ExtensionElement implements Element {
/// Return a list containing all of the methods declared in this extension.
List<MethodElement> get methods;

/// Return a list containing all of the type parameters declared by this
/// extension.
List<TypeParameterElement> get typeParameters;

/// Return the element representing the getter with the given [name] that is
/// declared in this extension, or `null` if this extension does not declare a
/// getter with the given name.
Expand Down Expand Up @@ -1100,6 +1098,11 @@ abstract class FieldElement
/// Return `true` if this element is an enum constant.
bool get isEnumConstant;

/// Return `true` if this element is a static element. A static element is an
/// element that is not associated with a particular instance, but rather with
/// an entire library or class.
bool get isStatic;

/// Returns `true` if this field can be overridden in strong mode.
@deprecated
bool get isVirtual;
Expand Down Expand Up @@ -1191,7 +1194,7 @@ abstract class FunctionTypedElement implements TypeParameterizedElement {
/// return type was explicitly specified.
DartType get returnType;

@override
/// Return the type defined by this element.
FunctionType get type;
}

Expand Down Expand Up @@ -1674,9 +1677,6 @@ abstract class TypeParameterizedElement implements Element {
/// If the element does not define a type, returns `true`.
bool get isSimplyBounded;

/// The type of this element, which will be a parameterized type.
ParameterizedType get type;

/// Return a list containing all of the type parameters declared by this
/// element directly. This does not include type parameters that are declared
/// by any enclosing elements.
Expand Down
3 changes: 2 additions & 1 deletion pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,8 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
// lookup for ==
MethodElement method =
element.lookUpConcreteMethod("==", _currentLibrary);
if (method == null || method.enclosingElement.type.isObject) {
if (method == null ||
(method.enclosingElement as ClassElement).type.isObject) {
return false;
}
// there is == that we don't like
Expand Down
150 changes: 59 additions & 91 deletions pkg/analyzer/lib/src/dart/element/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4926,12 +4926,11 @@ class ExportElementImpl extends UriReferencedElementImpl
}

/// A concrete implementation of an [ExtensionElement].
class ExtensionElementImpl extends ElementImpl implements ExtensionElement {
class ExtensionElementImpl extends ElementImpl
with TypeParameterizedElementMixin
implements ExtensionElement {
/// The unlinked representation of the extension in the summary.
final /* UnlinkedExtension */ _unlinkedExtension;

/// A list containing all of the type parameters declared by this extension.
List<TypeParameterElement> _typeParameters;
final UnlinkedExtension _unlinkedExtension;

/// The type being extended.
DartType _extendedType;
Expand Down Expand Up @@ -4991,6 +4990,9 @@ class ExtensionElementImpl extends ElementImpl implements ExtensionElement {
_accessors = accessors;
}

@override
TypeParameterizedElementMixin get enclosingTypeParameterContext => null;

@override
DartType get extendedType {
if (_extendedType != null) {
Expand All @@ -5014,6 +5016,9 @@ class ExtensionElementImpl extends ElementImpl implements ExtensionElement {
_extendedType = extendedType;
}

@override
bool get isSimplyBounded => true;

@override
ElementKind get kind => ElementKind.EXTENSION;

Expand All @@ -5024,49 +5029,47 @@ class ExtensionElementImpl extends ElementImpl implements ExtensionElement {
}

if (linkedNode != null) {
// TODO(brianwilkerson) Implement this.
// var context = enclosingUnit.linkedContext;
// var containerRef = reference.getChild('@method');
// return _methods = context
// .getMethods(linkedNode)
// .where((node) => node.propertyKeyword == null)
// .map((node) {
// var name = node.name.name;
// var reference = containerRef.getChild(name);
// if (reference.hasElementFor(node)) {
// return reference.element as MethodElement;
// }
// return MethodElementImpl.forLinkedNode(this, reference, node);
// }).toList();
var context = enclosingUnit.linkedContext;
var containerRef = reference.getChild('@method');
return _methods = context
.getMethods(linkedNode)
.where((node) => node.propertyKeyword == null)
.map((node) {
var name = node.name.name;
var reference = containerRef.getChild(name);
if (reference.hasElementFor(node)) {
return reference.element as MethodElement;
}
return MethodElementImpl.forLinkedNode(this, reference, node);
}).toList();
} else if (_unlinkedExtension != null) {
// TODO(brianwilkerson) Implement this.
// var unlinkedExecutables = _unlinkedExtension.executables;
//
// var length = unlinkedExecutables.length;
// if (length == 0) {
// return _methods = const <MethodElement>[];
// }
//
// var count = 0;
// for (var i = 0; i < length; i++) {
// var e = unlinkedExecutables[i];
// if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
// count++;
// }
// }
// if (count == 0) {
// return _methods = const <MethodElement>[];
// }
//
// var methods = new List<MethodElement>(count);
// var index = 0;
// for (var i = 0; i < length; i++) {
// var e = unlinkedExecutables[i];
// if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
// methods[index++] = new MethodElementImpl.forSerialized(e, this);
// }
// }
// return _methods = methods;
var unlinkedExecutables = _unlinkedExtension.executables;

var length = unlinkedExecutables.length;
if (length == 0) {
return _methods = const <MethodElement>[];
}

var count = 0;
for (var i = 0; i < length; i++) {
var e = unlinkedExecutables[i];
if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
count++;
}
}
if (count == 0) {
return _methods = const <MethodElement>[];
}

var methods = new List<MethodElement>(count);
var index = 0;
for (var i = 0; i < length; i++) {
var e = unlinkedExecutables[i];
if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
methods[index++] = new MethodElementImpl.forSerialized(e, this);
}
}
return _methods = methods;
}
return _methods = const <MethodElement>[];
}
Expand Down Expand Up @@ -5104,52 +5107,20 @@ class ExtensionElementImpl extends ElementImpl implements ExtensionElement {
return offset;
}

@override
List<TypeParameterElement> get typeParameters {
if (_typeParameters != null) {
return _typeParameters;
}

if (linkedNode != null) {
var typeParameters = linkedContext.getTypeParameters2(linkedNode);
if (typeParameters == null) {
return _typeParameters = const [];
}
var containerRef = reference.getChild('@typeParameter');
return _typeParameters =
typeParameters.typeParameters.map<TypeParameterElement>((node) {
var reference = containerRef.getChild(node.name.name);
if (reference.hasElementFor(node)) {
return reference.element as TypeParameterElement;
}
return TypeParameterElementImpl.forLinkedNode(this, reference, node);
}).toList();
} else if (_unlinkedExtension != null) {
List<UnlinkedTypeParam> unlinkedParams =
_unlinkedExtension?.typeParameters;
if (unlinkedParams != null) {
int numTypeParameters = unlinkedParams.length;
_typeParameters = new List<TypeParameterElement>(numTypeParameters);
for (int i = 0; i < numTypeParameters; i++) {
_typeParameters[i] = new TypeParameterElementImpl.forSerialized(
unlinkedParams[i], this);
}
}
}

return _typeParameters ?? const <TypeParameterElement>[];
}

/// Set the type parameters defined by this extension to the given
/// [typeParameters].
void set typeParameters(List<TypeParameterElement> typeParameters) {
_assertNotResynthesized(_unlinkedExtension);
for (TypeParameterElement typeParameter in typeParameters) {
(typeParameter as TypeParameterElementImpl).enclosingElement = this;
}
this._typeParameters = typeParameters;
this._typeParameterElements = typeParameters;
}

@override
List<UnlinkedTypeParam> get unlinkedTypeParams =>
_unlinkedExtension?.typeParameters;

@override
T accept<T>(ElementVisitor<T> visitor) {
return visitor.visitExtensionElement(this);
Expand Down Expand Up @@ -7499,16 +7470,16 @@ class MethodElementImpl extends ExecutableElementImpl implements MethodElement {
/// given [offset].
MethodElementImpl(String name, int offset) : super(name, offset);

MethodElementImpl.forLinkedNode(ClassElementImpl enclosingClass,
MethodElementImpl.forLinkedNode(TypeParameterizedElementMixin enclosingClass,
Reference reference, MethodDeclaration linkedNode)
: super.forLinkedNode(enclosingClass, reference, linkedNode);

/// Initialize a newly created method element to have the given [name].
MethodElementImpl.forNode(Identifier name) : super.forNode(name);

/// Initialize using the given serialized information.
MethodElementImpl.forSerialized(
UnlinkedExecutable serializedExecutable, ClassElementImpl enclosingClass)
MethodElementImpl.forSerialized(UnlinkedExecutable serializedExecutable,
TypeParameterizedElementMixin enclosingClass)
: super.forSerialized(serializedExecutable, enclosingClass);

@override
Expand All @@ -7520,12 +7491,9 @@ class MethodElementImpl extends ExecutableElementImpl implements MethodElement {
return displayName;
}

@override
ClassElement get enclosingElement => super.enclosingElement as ClassElement;

@override
TypeParameterizedElementMixin get enclosingTypeParameterContext =>
super.enclosingElement as ClassElementImpl;
super.enclosingElement as TypeParameterizedElementMixin;

/// Set whether this class is abstract.
void set isAbstract(bool isAbstract) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/analyzer/lib/src/dart/element/member.dart
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ class FieldFormalParameterMember extends ParameterMember
FieldElement field = (baseElement as FieldFormalParameterElement).field;
if (field is FieldElement) {
return FieldMember.from(
field, substituteFor(field.enclosingElement.type));
field, substituteFor((field.enclosingElement as ClassElement).type));
}
return field;
}
Expand Down
2 changes: 0 additions & 2 deletions pkg/analyzer/test/util/element_type_matchers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import 'package:test/test.dart';

const isClassElement = const TypeMatcher<ClassElement>();

const isClassMemberElement = const TypeMatcher<ClassMemberElement>();

const isCompilationUnitElement = const TypeMatcher<CompilationUnitElement>();

const isConstructorElement = const TypeMatcher<ConstructorElement>();
Expand Down
11 changes: 7 additions & 4 deletions pkg/dev_compiler/lib/src/analyzer/code_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3105,7 +3105,7 @@ class CodeGenerator extends Object
js_ast.Expression _emitClassMemberElement(
ClassMemberElement element, Element accessor, Expression node) {
bool isStatic = element.isStatic;
var classElem = element.enclosingElement;
var classElem = element.enclosingElement as ClassElement;
var type = classElem.type;
var member = _emitMemberName(element.name,
isStatic: isStatic, type: type, element: accessor);
Expand Down Expand Up @@ -3300,7 +3300,7 @@ class CodeGenerator extends Object
/// [_emitTopLevelName] on the class, but if the member is external, then the
/// native class name will be used, for direct access to the native member.
js_ast.Expression _emitStaticClassName(ClassMemberElement member) {
var c = member.enclosingElement;
var c = member.enclosingElement as ClassElement;
_declareBeforeUse(c);

// A static native element should just forward directly to the JS type's
Expand Down Expand Up @@ -3593,7 +3593,7 @@ class CodeGenerator extends Object
/// Emits assignment to a static field element or property.
js_ast.Expression _emitSetField(Expression right, FieldElement field,
js_ast.Expression jsTarget, SimpleIdentifier id) {
var classElem = field.enclosingElement;
var classElem = field.enclosingElement as ClassElement;
var isStatic = field.isStatic;
var member = _emitMemberName(field.name,
isStatic: isStatic, type: classElem.type, element: field.setter);
Expand Down Expand Up @@ -4577,7 +4577,10 @@ class CodeGenerator extends Object
DartType getType(TypeAnnotation typeNode) {
if (typeNode is NamedType && typeNode.typeArguments != null) {
var e = typeNode.name.staticElement;
if (e is TypeParameterizedElement) {
if (e is ClassElement) {
return e.type.instantiate(
typeNode.typeArguments.arguments.map(getType).toList());
} else if (e is FunctionTypedElement) {
return e.type.instantiate(
typeNode.typeArguments.arguments.map(getType).toList());
}
Expand Down
11 changes: 9 additions & 2 deletions pkg/dev_compiler/lib/src/analyzer/element_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@ DartType instantiateElementTypeToBounds(
// Futhermore, the second line is represented by a GenericTypeAliasElement,
// and its type getter does not even include its own type formals `<S>`.
// That has to be worked around using `.function.type`.
var type = e is GenericTypeAliasElement ? e.function.type : e.type;
DartType type;
if (e is GenericTypeAliasElement) {
type = e.function.type;
} else if (e is FunctionTypedElement) {
type = e.type;
} else if (e is ClassElement) {
type = e.type;
}
var bounds = rules.instantiateTypeFormalsToBounds(e.typeParameters);
if (bounds == null) return type;
return type.substitute2(
Expand Down Expand Up @@ -220,7 +227,7 @@ bool hasNoSuchMethod(ClassElement classElement) {
var method = classElement.lookUpMethod(
FunctionElement.NO_SUCH_METHOD_METHOD_NAME, classElement.library);
var definingClass = method?.enclosingElement;
return definingClass != null && !definingClass.type.isObject;
return definingClass is ClassElement && !definingClass.type.isObject;
}

/// Returns true if this class is of the form:
Expand Down
Loading

0 comments on commit 97587b5

Please sign in to comment.