Skip to content

Commit 97587b5

Browse files
bwilkersoncommit-bot@chromium.org
authored andcommitted
Update the element model to support extension methods
Change-Id: Ia3bd6a19514368b3e046fead2eed0a4d0bfb133d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/108504 Reviewed-by: Phil Quitslund <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent a8331cd commit 97587b5

File tree

9 files changed

+98
-120
lines changed

9 files changed

+98
-120
lines changed

pkg/analyzer/lib/dart/element/element.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,8 @@ abstract class ClassElement
349349
///
350350
/// Clients may not extend, implement or mix-in this class.
351351
abstract class ClassMemberElement implements Element {
352-
@override
353-
ClassElement get enclosingElement;
354-
352+
// TODO(brianwilkerson) Either remove this class or rename it to something
353+
// more correct, such as PotentiallyStaticElement.
355354
/// Return `true` if this element is a static element. A static element is an
356355
/// element that is not associated with a particular instance, but rather with
357356
/// an entire library or class.
@@ -425,6 +424,9 @@ abstract class CompilationUnitElement implements Element, UriReferencedElement {
425424
/// Clients may not extend, implement or mix-in this class.
426425
abstract class ConstructorElement
427426
implements ClassMemberElement, ExecutableElement, ConstantEvaluationTarget {
427+
@override
428+
ClassElement get enclosingElement;
429+
428430
/// Return `true` if this constructor is a const constructor.
429431
bool get isConst;
430432

@@ -1058,7 +1060,7 @@ abstract class ExportElement implements Element, UriReferencedElement {
10581060
/// An element that represents an extension.
10591061
///
10601062
/// Clients may not extend, implement or mix-in this class.
1061-
abstract class ExtensionElement implements Element {
1063+
abstract class ExtensionElement implements TypeParameterizedElement {
10621064
/// Return a list containing all of the accessors (getters and setters)
10631065
/// declared in this extension.
10641066
List<PropertyAccessorElement> get accessors;
@@ -1069,10 +1071,6 @@ abstract class ExtensionElement implements Element {
10691071
/// Return a list containing all of the methods declared in this extension.
10701072
List<MethodElement> get methods;
10711073

1072-
/// Return a list containing all of the type parameters declared by this
1073-
/// extension.
1074-
List<TypeParameterElement> get typeParameters;
1075-
10761074
/// Return the element representing the getter with the given [name] that is
10771075
/// declared in this extension, or `null` if this extension does not declare a
10781076
/// getter with the given name.
@@ -1100,6 +1098,11 @@ abstract class FieldElement
11001098
/// Return `true` if this element is an enum constant.
11011099
bool get isEnumConstant;
11021100

1101+
/// Return `true` if this element is a static element. A static element is an
1102+
/// element that is not associated with a particular instance, but rather with
1103+
/// an entire library or class.
1104+
bool get isStatic;
1105+
11031106
/// Returns `true` if this field can be overridden in strong mode.
11041107
@deprecated
11051108
bool get isVirtual;
@@ -1191,7 +1194,7 @@ abstract class FunctionTypedElement implements TypeParameterizedElement {
11911194
/// return type was explicitly specified.
11921195
DartType get returnType;
11931196

1194-
@override
1197+
/// Return the type defined by this element.
11951198
FunctionType get type;
11961199
}
11971200

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

1677-
/// The type of this element, which will be a parameterized type.
1678-
ParameterizedType get type;
1679-
16801680
/// Return a list containing all of the type parameters declared by this
16811681
/// element directly. This does not include type parameters that are declared
16821682
/// by any enclosing elements.

pkg/analyzer/lib/src/dart/constant/constant_verifier.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,8 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
348348
// lookup for ==
349349
MethodElement method =
350350
element.lookUpConcreteMethod("==", _currentLibrary);
351-
if (method == null || method.enclosingElement.type.isObject) {
351+
if (method == null ||
352+
(method.enclosingElement as ClassElement).type.isObject) {
352353
return false;
353354
}
354355
// there is == that we don't like

pkg/analyzer/lib/src/dart/element/element.dart

Lines changed: 59 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -4926,12 +4926,11 @@ class ExportElementImpl extends UriReferencedElementImpl
49264926
}
49274927

49284928
/// A concrete implementation of an [ExtensionElement].
4929-
class ExtensionElementImpl extends ElementImpl implements ExtensionElement {
4929+
class ExtensionElementImpl extends ElementImpl
4930+
with TypeParameterizedElementMixin
4931+
implements ExtensionElement {
49304932
/// The unlinked representation of the extension in the summary.
4931-
final /* UnlinkedExtension */ _unlinkedExtension;
4932-
4933-
/// A list containing all of the type parameters declared by this extension.
4934-
List<TypeParameterElement> _typeParameters;
4933+
final UnlinkedExtension _unlinkedExtension;
49354934

49364935
/// The type being extended.
49374936
DartType _extendedType;
@@ -4991,6 +4990,9 @@ class ExtensionElementImpl extends ElementImpl implements ExtensionElement {
49914990
_accessors = accessors;
49924991
}
49934992

4993+
@override
4994+
TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
4995+
49944996
@override
49954997
DartType get extendedType {
49964998
if (_extendedType != null) {
@@ -5014,6 +5016,9 @@ class ExtensionElementImpl extends ElementImpl implements ExtensionElement {
50145016
_extendedType = extendedType;
50155017
}
50165018

5019+
@override
5020+
bool get isSimplyBounded => true;
5021+
50175022
@override
50185023
ElementKind get kind => ElementKind.EXTENSION;
50195024

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

50265031
if (linkedNode != null) {
5027-
// TODO(brianwilkerson) Implement this.
5028-
// var context = enclosingUnit.linkedContext;
5029-
// var containerRef = reference.getChild('@method');
5030-
// return _methods = context
5031-
// .getMethods(linkedNode)
5032-
// .where((node) => node.propertyKeyword == null)
5033-
// .map((node) {
5034-
// var name = node.name.name;
5035-
// var reference = containerRef.getChild(name);
5036-
// if (reference.hasElementFor(node)) {
5037-
// return reference.element as MethodElement;
5038-
// }
5039-
// return MethodElementImpl.forLinkedNode(this, reference, node);
5040-
// }).toList();
5032+
var context = enclosingUnit.linkedContext;
5033+
var containerRef = reference.getChild('@method');
5034+
return _methods = context
5035+
.getMethods(linkedNode)
5036+
.where((node) => node.propertyKeyword == null)
5037+
.map((node) {
5038+
var name = node.name.name;
5039+
var reference = containerRef.getChild(name);
5040+
if (reference.hasElementFor(node)) {
5041+
return reference.element as MethodElement;
5042+
}
5043+
return MethodElementImpl.forLinkedNode(this, reference, node);
5044+
}).toList();
50415045
} else if (_unlinkedExtension != null) {
5042-
// TODO(brianwilkerson) Implement this.
5043-
// var unlinkedExecutables = _unlinkedExtension.executables;
5044-
//
5045-
// var length = unlinkedExecutables.length;
5046-
// if (length == 0) {
5047-
// return _methods = const <MethodElement>[];
5048-
// }
5049-
//
5050-
// var count = 0;
5051-
// for (var i = 0; i < length; i++) {
5052-
// var e = unlinkedExecutables[i];
5053-
// if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
5054-
// count++;
5055-
// }
5056-
// }
5057-
// if (count == 0) {
5058-
// return _methods = const <MethodElement>[];
5059-
// }
5060-
//
5061-
// var methods = new List<MethodElement>(count);
5062-
// var index = 0;
5063-
// for (var i = 0; i < length; i++) {
5064-
// var e = unlinkedExecutables[i];
5065-
// if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
5066-
// methods[index++] = new MethodElementImpl.forSerialized(e, this);
5067-
// }
5068-
// }
5069-
// return _methods = methods;
5046+
var unlinkedExecutables = _unlinkedExtension.executables;
5047+
5048+
var length = unlinkedExecutables.length;
5049+
if (length == 0) {
5050+
return _methods = const <MethodElement>[];
5051+
}
5052+
5053+
var count = 0;
5054+
for (var i = 0; i < length; i++) {
5055+
var e = unlinkedExecutables[i];
5056+
if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
5057+
count++;
5058+
}
5059+
}
5060+
if (count == 0) {
5061+
return _methods = const <MethodElement>[];
5062+
}
5063+
5064+
var methods = new List<MethodElement>(count);
5065+
var index = 0;
5066+
for (var i = 0; i < length; i++) {
5067+
var e = unlinkedExecutables[i];
5068+
if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
5069+
methods[index++] = new MethodElementImpl.forSerialized(e, this);
5070+
}
5071+
}
5072+
return _methods = methods;
50705073
}
50715074
return _methods = const <MethodElement>[];
50725075
}
@@ -5104,52 +5107,20 @@ class ExtensionElementImpl extends ElementImpl implements ExtensionElement {
51045107
return offset;
51055108
}
51065109

5107-
@override
5108-
List<TypeParameterElement> get typeParameters {
5109-
if (_typeParameters != null) {
5110-
return _typeParameters;
5111-
}
5112-
5113-
if (linkedNode != null) {
5114-
var typeParameters = linkedContext.getTypeParameters2(linkedNode);
5115-
if (typeParameters == null) {
5116-
return _typeParameters = const [];
5117-
}
5118-
var containerRef = reference.getChild('@typeParameter');
5119-
return _typeParameters =
5120-
typeParameters.typeParameters.map<TypeParameterElement>((node) {
5121-
var reference = containerRef.getChild(node.name.name);
5122-
if (reference.hasElementFor(node)) {
5123-
return reference.element as TypeParameterElement;
5124-
}
5125-
return TypeParameterElementImpl.forLinkedNode(this, reference, node);
5126-
}).toList();
5127-
} else if (_unlinkedExtension != null) {
5128-
List<UnlinkedTypeParam> unlinkedParams =
5129-
_unlinkedExtension?.typeParameters;
5130-
if (unlinkedParams != null) {
5131-
int numTypeParameters = unlinkedParams.length;
5132-
_typeParameters = new List<TypeParameterElement>(numTypeParameters);
5133-
for (int i = 0; i < numTypeParameters; i++) {
5134-
_typeParameters[i] = new TypeParameterElementImpl.forSerialized(
5135-
unlinkedParams[i], this);
5136-
}
5137-
}
5138-
}
5139-
5140-
return _typeParameters ?? const <TypeParameterElement>[];
5141-
}
5142-
51435110
/// Set the type parameters defined by this extension to the given
51445111
/// [typeParameters].
51455112
void set typeParameters(List<TypeParameterElement> typeParameters) {
51465113
_assertNotResynthesized(_unlinkedExtension);
51475114
for (TypeParameterElement typeParameter in typeParameters) {
51485115
(typeParameter as TypeParameterElementImpl).enclosingElement = this;
51495116
}
5150-
this._typeParameters = typeParameters;
5117+
this._typeParameterElements = typeParameters;
51515118
}
51525119

5120+
@override
5121+
List<UnlinkedTypeParam> get unlinkedTypeParams =>
5122+
_unlinkedExtension?.typeParameters;
5123+
51535124
@override
51545125
T accept<T>(ElementVisitor<T> visitor) {
51555126
return visitor.visitExtensionElement(this);
@@ -7499,16 +7470,16 @@ class MethodElementImpl extends ExecutableElementImpl implements MethodElement {
74997470
/// given [offset].
75007471
MethodElementImpl(String name, int offset) : super(name, offset);
75017472

7502-
MethodElementImpl.forLinkedNode(ClassElementImpl enclosingClass,
7473+
MethodElementImpl.forLinkedNode(TypeParameterizedElementMixin enclosingClass,
75037474
Reference reference, MethodDeclaration linkedNode)
75047475
: super.forLinkedNode(enclosingClass, reference, linkedNode);
75057476

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

75097480
/// Initialize using the given serialized information.
7510-
MethodElementImpl.forSerialized(
7511-
UnlinkedExecutable serializedExecutable, ClassElementImpl enclosingClass)
7481+
MethodElementImpl.forSerialized(UnlinkedExecutable serializedExecutable,
7482+
TypeParameterizedElementMixin enclosingClass)
75127483
: super.forSerialized(serializedExecutable, enclosingClass);
75137484

75147485
@override
@@ -7520,12 +7491,9 @@ class MethodElementImpl extends ExecutableElementImpl implements MethodElement {
75207491
return displayName;
75217492
}
75227493

7523-
@override
7524-
ClassElement get enclosingElement => super.enclosingElement as ClassElement;
7525-
75267494
@override
75277495
TypeParameterizedElementMixin get enclosingTypeParameterContext =>
7528-
super.enclosingElement as ClassElementImpl;
7496+
super.enclosingElement as TypeParameterizedElementMixin;
75297497

75307498
/// Set whether this class is abstract.
75317499
void set isAbstract(bool isAbstract) {

pkg/analyzer/lib/src/dart/element/member.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ class FieldFormalParameterMember extends ParameterMember
215215
FieldElement field = (baseElement as FieldFormalParameterElement).field;
216216
if (field is FieldElement) {
217217
return FieldMember.from(
218-
field, substituteFor(field.enclosingElement.type));
218+
field, substituteFor((field.enclosingElement as ClassElement).type));
219219
}
220220
return field;
221221
}

pkg/analyzer/test/util/element_type_matchers.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import 'package:test/test.dart';
77

88
const isClassElement = const TypeMatcher<ClassElement>();
99

10-
const isClassMemberElement = const TypeMatcher<ClassMemberElement>();
11-
1210
const isCompilationUnitElement = const TypeMatcher<CompilationUnitElement>();
1311

1412
const isConstructorElement = const TypeMatcher<ConstructorElement>();

pkg/dev_compiler/lib/src/analyzer/code_generator.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3105,7 +3105,7 @@ class CodeGenerator extends Object
31053105
js_ast.Expression _emitClassMemberElement(
31063106
ClassMemberElement element, Element accessor, Expression node) {
31073107
bool isStatic = element.isStatic;
3108-
var classElem = element.enclosingElement;
3108+
var classElem = element.enclosingElement as ClassElement;
31093109
var type = classElem.type;
31103110
var member = _emitMemberName(element.name,
31113111
isStatic: isStatic, type: type, element: accessor);
@@ -3300,7 +3300,7 @@ class CodeGenerator extends Object
33003300
/// [_emitTopLevelName] on the class, but if the member is external, then the
33013301
/// native class name will be used, for direct access to the native member.
33023302
js_ast.Expression _emitStaticClassName(ClassMemberElement member) {
3303-
var c = member.enclosingElement;
3303+
var c = member.enclosingElement as ClassElement;
33043304
_declareBeforeUse(c);
33053305

33063306
// A static native element should just forward directly to the JS type's
@@ -3593,7 +3593,7 @@ class CodeGenerator extends Object
35933593
/// Emits assignment to a static field element or property.
35943594
js_ast.Expression _emitSetField(Expression right, FieldElement field,
35953595
js_ast.Expression jsTarget, SimpleIdentifier id) {
3596-
var classElem = field.enclosingElement;
3596+
var classElem = field.enclosingElement as ClassElement;
35973597
var isStatic = field.isStatic;
35983598
var member = _emitMemberName(field.name,
35993599
isStatic: isStatic, type: classElem.type, element: field.setter);
@@ -4577,7 +4577,10 @@ class CodeGenerator extends Object
45774577
DartType getType(TypeAnnotation typeNode) {
45784578
if (typeNode is NamedType && typeNode.typeArguments != null) {
45794579
var e = typeNode.name.staticElement;
4580-
if (e is TypeParameterizedElement) {
4580+
if (e is ClassElement) {
4581+
return e.type.instantiate(
4582+
typeNode.typeArguments.arguments.map(getType).toList());
4583+
} else if (e is FunctionTypedElement) {
45814584
return e.type.instantiate(
45824585
typeNode.typeArguments.arguments.map(getType).toList());
45834586
}

pkg/dev_compiler/lib/src/analyzer/element_helpers.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,14 @@ DartType instantiateElementTypeToBounds(
5757
// Futhermore, the second line is represented by a GenericTypeAliasElement,
5858
// and its type getter does not even include its own type formals `<S>`.
5959
// That has to be worked around using `.function.type`.
60-
var type = e is GenericTypeAliasElement ? e.function.type : e.type;
60+
DartType type;
61+
if (e is GenericTypeAliasElement) {
62+
type = e.function.type;
63+
} else if (e is FunctionTypedElement) {
64+
type = e.type;
65+
} else if (e is ClassElement) {
66+
type = e.type;
67+
}
6168
var bounds = rules.instantiateTypeFormalsToBounds(e.typeParameters);
6269
if (bounds == null) return type;
6370
return type.substitute2(
@@ -220,7 +227,7 @@ bool hasNoSuchMethod(ClassElement classElement) {
220227
var method = classElement.lookUpMethod(
221228
FunctionElement.NO_SUCH_METHOD_METHOD_NAME, classElement.library);
222229
var definingClass = method?.enclosingElement;
223-
return definingClass != null && !definingClass.type.isObject;
230+
return definingClass is ClassElement && !definingClass.type.isObject;
224231
}
225232

226233
/// Returns true if this class is of the form:

0 commit comments

Comments
 (0)