Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(769)

Unified Diff: lib/compiler/implementation/elements/elements.dart

Issue 10905305: Patch refactoring. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased. Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: lib/compiler/implementation/elements/elements.dart
diff --git a/lib/compiler/implementation/elements/elements.dart b/lib/compiler/implementation/elements/elements.dart
index 9786f92eb052f78a0695bc86f3e848e28aff688d..390d775f5e8968ba4bcdcb888eff0d33fd086f3a 100644
--- a/lib/compiler/implementation/elements/elements.dart
+++ b/lib/compiler/implementation/elements/elements.dart
@@ -114,13 +114,13 @@ class Element implements Spannable {
Link<MetadataAnnotation> metadata = const EmptyLink<MetadataAnnotation>();
Element(this.name, this.kind, this.enclosingElement) {
- assert(getLibrary() !== null);
+ assert(isErroneous() || getImplementationLibrary() !== null);
}
Modifiers get modifiers => Modifiers.EMPTY;
Node parseNode(DiagnosticListener listener) {
- listener.cancel("Internal Error: $this.parseNode", token: position());
+ listener.internalErrorOnElement(this, 'not implemented');
}
DartType computeType(Compiler compiler) {
@@ -189,21 +189,20 @@ class Element implements Spannable {
*/
bool get isPatch => false;
-
/**
* Is [:true:] if this element defines the implementation for the entity of
* this element.
*
* See [:patch_parser.dart:] for a description of the terminology.
*/
- bool get isImplementation => implementation === this;
+ bool get isImplementation => !isPatched;
/**
* Is [:true:] if this element introduces the entity of this element.
*
* See [:patch_parser.dart:] for a description of the terminology.
*/
- bool get isDeclaration => declaration === this;
+ bool get isDeclaration => !isPatch;
/**
* Returns the element which defines the implementation for the entity of this
@@ -211,14 +210,14 @@ class Element implements Spannable {
*
* See [:patch_parser.dart:] for a description of the terminology.
*/
- Element get implementation => this;
+ Element get implementation => isPatched ? patch : this;
/**
* Returns the element which introduces the entity of this element.
*
* See [:patch_parser.dart:] for a description of the terminology.
*/
- Element get declaration => this;
+ Element get declaration => isPatch ? origin : this;
// TODO(johnniwinther): This breaks for libraries (for which enclosing
// elements are null) and is invalid for top level variable declarations for
@@ -260,17 +259,13 @@ class Element implements Spannable {
return library.entryCompilationUnit;
}
element = element.enclosingElement;
- if (element is FunctionElement) {
- FunctionElement function = element;
- if (function.isPatched) {
- element = function.patch;
- }
- }
}
return element;
}
- LibraryElement getLibrary() {
+ LibraryElement getLibrary() => enclosingElement.getLibrary();
+
+ LibraryElement getImplementationLibrary() {
Element element = this;
while (element.kind !== ElementKind.LIBRARY) {
element = element.enclosingElement;
@@ -278,8 +273,6 @@ class Element implements Spannable {
return element;
}
- LibraryElement getImplementationLibrary() => getLibrary();
-
ClassElement getEnclosingClass() {
for (Element e = this; e !== null; e = e.enclosingElement) {
if (e.isClass()) return e;
@@ -315,12 +308,17 @@ class Element implements Spannable {
* Creates the scope for this element. The scope of the
* enclosing element will be the parent scope.
*/
- Scope buildScope() => buildEnclosingScope();
+ // TODO(johnniwinther): Clean up scope generation. Possibly generation scopes
+ // externally.
+ Scope buildScope({bool patchScope: false}) =>
+ buildEnclosingScope(patchScope: patchScope);
/**
* Creates the scope for the enclosing element.
*/
- Scope buildEnclosingScope() => enclosingElement.buildScope();
+ // TODO(johnniwinther): Remove buildEnclosingScope as part of scope clean-up.
+ Scope buildEnclosingScope({bool patchScope: false}) =>
+ enclosingElement.buildScope(patchScope: patchScope);
String toString() {
// TODO(johnniwinther): Test for nullness of name, or make non-nullness an
@@ -342,6 +340,7 @@ class Element implements Spannable {
FunctionElement asFunctionElement() => null;
+ static bool isInvalid(Element e) => e == null || e.isErroneous();
Element cloneTo(Element enclosing, DiagnosticListener listener) {
listener.cancel("Unimplemented cloneTo", element: this);
}
@@ -444,7 +443,11 @@ class ScopeContainerElement extends ContainerElement {
}
Element localLookup(SourceString elementName) {
- return localScope[elementName];
+ Element result = localScope[elementName];
+ if (result == null && isPatch) {
+ result = origin.localScope[elementName];
+ }
+ return result;
}
/**
@@ -517,7 +520,11 @@ class CompilationUnitElement extends ContainerElement {
// Keep a list of top level members.
super.addMember(element, listener);
// Provide the member to the library to build scope.
- getLibrary().addMember(element, listener);
+ if (enclosingElement.isPatch) {
+ getImplementationLibrary().addMember(element, listener);
+ } else {
+ getLibrary().addMember(element, listener);
+ }
}
}
@@ -540,9 +547,22 @@ class LibraryElement extends ScopeContainerElement {
Link<LibraryTag> tags = const EmptyLink<LibraryTag>();
LibraryTag libraryTag;
bool canUseNative = false;
+
+ /**
+ * If this library is patched, [patch] points to the patch library.
+ *
+ * See [:patch_parser.dart:] for a description of the terminology.
+ */
LibraryElement patch = null;
/**
+ * If this is a patch library, [origin] points to the origin library.
+ *
+ * See [:patch_parser.dart:] for a description of the terminology.
+ */
+ final LibraryElement origin;
+
+ /**
* Map for elements imported through import declarations.
*
* Addition to the map is performed by [addImport]. Lookup is done trough
@@ -550,15 +570,21 @@ class LibraryElement extends ScopeContainerElement {
*/
final Map<SourceString, Element> importScope;
- LibraryElement(Script script, [Uri uri])
+ LibraryElement(Script script, [Uri uri, LibraryElement this.origin])
: this.uri = ((uri === null) ? script.uri : uri),
importScope = new Map<SourceString, Element>(),
super(new SourceString(script.name), ElementKind.LIBRARY, null) {
entryCompilationUnit = new CompilationUnitElement(script, this);
+ if (isPatch) {
+ origin.patch = this;
+ }
}
-
bool get isPatched => patch !== null;
+ bool get isPatch => origin !== null;
+
+ LibraryElement get declaration => super.declaration;
+ LibraryElement get implementation => super.implementation;
void addCompilationUnit(CompilationUnitElement element) {
compilationUnits = compilationUnits.prepend(element);
@@ -588,6 +614,7 @@ class LibraryElement extends ScopeContainerElement {
}
}
+ LibraryElement getLibrary() => isPatch ? origin : this;
/**
* Look up a top-level element in this library. The element could
@@ -606,6 +633,8 @@ class LibraryElement extends ScopeContainerElement {
/** Look up a top-level element in this library, but only look for
* non-imported elements. Returns null if no such element exist. */
Element findLocal(SourceString elementName) {
+ // TODO(johnniwinther): How to handle injected elements in the patch
+ // library?
Element result = localScope[elementName];
if (result === null || result.getLibrary() != this) return null;
return result;
@@ -622,6 +651,23 @@ class LibraryElement extends ScopeContainerElement {
});
}
+ void forEachLocalMember(f(Element element)) {
+ if (isPatch) {
+ // Patch libraries traverse both origin and injected members.
+ origin.localMembers.forEach(f);
+
+ void filterPatch(Element element) {
+ if (!element.isPatch) {
+ // Do not traverse the patch members.
+ f(element);
+ }
+ }
+ localMembers.forEach(filterPatch);
+ } else {
+ localMembers.forEach(f);
+ }
+ }
+
bool hasLibraryName() => libraryTag !== null;
/**
@@ -639,9 +685,28 @@ class LibraryElement extends ScopeContainerElement {
}
}
- Scope buildEnclosingScope() => new TopScope(this);
+ // TODO(johnniwinther): Rewrite to avoid the optional argument.
+ Scope buildEnclosingScope({bool patchScope: false}) {
+ if (origin !== null) {
+ return new PatchLibraryScope(origin, this);
+ } if (patchScope && patch !== null) {
+ return new PatchLibraryScope(this, patch);
+ } else {
+ return new TopScope(this);
+ }
+ }
bool get isPlatformLibrary => uri.scheme == "dart";
+
+ String toString() {
+ if (origin !== null) {
+ return 'patch library(${getLibraryOrScriptName()})';
+ } else if (patch !== null) {
+ return 'origin library(${getLibraryOrScriptName()})';
+ } else {
+ return 'library(${getLibraryOrScriptName()})';
+ }
+ }
}
class PrefixElement extends Element {
@@ -696,8 +761,11 @@ class TypedefElement extends Element implements TypeDeclarationElement {
Link<DartType> get typeVariables => cachedType.typeArguments;
- Scope buildScope() =>
- new TypeDeclarationScope(enclosingElement.buildScope(), this);
+ // TODO(johnniwinther): Rewrite to avoid the optional argument.
+ Scope buildScope({bool patchScope: false}) {
+ return new TypeDeclarationScope(
+ enclosingElement.buildScope(patchScope: patchScope), this);
+ }
TypedefElement cloneTo(Element enclosing, DiagnosticListener listener) {
TypedefElement result = new TypedefElement(name, enclosing);
@@ -858,10 +926,12 @@ class VariableListElement extends Element {
return isMember() && !modifiers.isStatic();
}
- Scope buildScope() {
- Scope result = new VariableScope(enclosingElement.buildScope(), this);
+ // TODO(johnniwinther): Rewrite to avoid the optional argument.
+ Scope buildScope({bool patchScope: false}) {
+ Scope result = new VariableScope(
+ enclosingElement.buildScope(patchScope: patchScope), this);
if (enclosingElement.isClass()) {
- ClassScope clsScope = result.parent;
+ Scope clsScope = result.parent;
clsScope.inStaticContext = !isInstanceMember();
}
return result;
@@ -1012,6 +1082,7 @@ class FunctionElement extends Element {
*/
// TODO(lrn): Consider using [defaultImplementation] to store the patch.
FunctionElement patch = null;
+ FunctionElement origin = null;
/**
* If this is an interface constructor, [defaultImplementation] will
@@ -1052,6 +1123,7 @@ class FunctionElement extends Element {
}
bool get isPatched => patch !== null;
+ bool get isPatch => origin !== null;
/**
* Applies a patch function to this function. The patch function's body
@@ -1062,9 +1134,7 @@ class FunctionElement extends Element {
void setPatch(FunctionElement patchElement) {
// Sanity checks. The caller must check these things before calling.
assert(patch === null);
- assert(cachedNode === null);
this.patch = patchElement;
- cachedNode = patchElement.cachedNode;
}
bool isInstanceMember() {
@@ -1101,15 +1171,12 @@ class FunctionElement extends Element {
}
Node parseNode(DiagnosticListener listener) {
- if (cachedNode !== null) return cachedNode;
if (patch === null) {
if (modifiers.isExternal()) {
listener.cancel("Compiling external function with no implementation.",
element: this);
}
- return null;
}
- cachedNode = patch.parseNode(listener);
return cachedNode;
}
@@ -1127,11 +1194,12 @@ class FunctionElement extends Element {
}
}
- Scope buildScope() {
- Scope result =
- new MethodScope(enclosingElement.buildScope(), this);
+ // TODO(johnniwinther): Rewrite to avoid the optional argument.
+ Scope buildScope({bool patchScope: false}) {
+ Scope result = new MethodScope(
+ enclosingElement.buildScope(patchScope: patchScope), this);
if (enclosingElement.isClass()) {
- ClassScope clsScope = result.parent;
+ Scope clsScope = result.parent;
clsScope.inStaticContext = !isInstanceMember() && !isConstructor();
}
return result;
@@ -1255,6 +1323,7 @@ class ClassElement extends ScopeContainerElement
// Lazily applied patch of class members.
ClassElement patch = null;
+ ClassElement origin = null;
ClassElement(SourceString name, Element enclosing, this.id, int initialState)
: supertypeLoadState = initialState,
@@ -1263,15 +1332,24 @@ class ClassElement extends ScopeContainerElement
InterfaceType computeType(compiler) {
if (type == null) {
- ClassNode node = parseNode(compiler);
- Link<DartType> parameters =
- TypeDeclarationElement.createTypeVariables(this, node.typeParameters);
- type = new InterfaceType(this, parameters);
+ if (origin === null) {
+ ClassNode node = parseNode(compiler);
+ Link<DartType> parameters =
+ TypeDeclarationElement.createTypeVariables(this,
+ node.typeParameters);
+ type = new InterfaceType(this, parameters);
+ } else {
+ type = origin.computeType(compiler);
+ }
}
return type;
}
bool get isPatched => patch != null;
+ bool get isPatch => origin != null;
+
+ ClassElement get declaration => super.declaration;
+ ClassElement get implementation => super.implementation;
/**
* Return [:true:] if this element is the [:Object:] class for the [compiler].
@@ -1310,10 +1388,12 @@ class ClassElement extends ScopeContainerElement
*/
Element lookupSuperMemberInLibrary(SourceString memberName,
LibraryElement library) {
+ bool includeInjectedMembers = isPatch;
bool isPrivate = memberName.isPrivate();
for (ClassElement s = superclass; s != null; s = s.superclass) {
// Private members from a different library are not visible.
if (isPrivate && library !== s.getLibrary()) continue;
+ s = includeInjectedMembers ? s.implementation : s;
Element e = s.lookupLocalMember(memberName);
if (e === null) continue;
// Static members are not inherited.
@@ -1328,9 +1408,11 @@ class ClassElement extends ScopeContainerElement
Element lookupSuperInterfaceMember(SourceString memberName,
LibraryElement fromLibrary) {
+ bool includeInjectedMembers = isPatch;
bool isPrivate = memberName.isPrivate();
for (InterfaceType t in interfaces) {
ClassElement cls = t.element;
+ cls = includeInjectedMembers ? cls.implementation : cls;
Element e = cls.lookupLocalMember(memberName);
if (e === null) continue;
// Private members from a different library are not visible.
@@ -1348,6 +1430,9 @@ class ClassElement extends ScopeContainerElement
* This method is NOT to be used for resolving
* unqualified sends because it does not implement the scoping
* rules, where library scope comes before superclass scope.
+ *
+ * When called on the implementation element both members declared in the
+ * origin and the patch class are returned.
*/
Element lookupSelector(Selector selector) {
SourceString memberName = selector.name;
@@ -1430,9 +1515,10 @@ class ClassElement extends ScopeContainerElement
Link<Element> get constructors {
// TODO(ajohnsen): See if we can avoid this method at some point.
Link<Element> result = const EmptyLink<Element>();
- for (Element member in localMembers) {
+ // TODO(johnniwinther): Should we include injected constructors?
+ forEachMember((_, Element member) {
if (member.isConstructor()) result = result.prepend(member);
- }
+ });
return result;
}
@@ -1451,12 +1537,17 @@ class ClassElement extends ScopeContainerElement
*
* The enclosing class is passed to the callback. This is useful when
* [includeSuperMembers] is [:true:].
+ *
+ * When called on an implementation element both the members in the origin
+ * and patch class are included.
*/
+ // TODO(johnniwinther): Clean up lookup to get rid of the include predicates.
void forEachMember([void f(ClassElement enclosingClass, Element member),
includeBackendMembers = false,
includeSuperMembers = false]) {
+ bool includeInjectedMembers = isPatch;
Set<ClassElement> seen = new Set<ClassElement>();
- ClassElement classElement = this;
+ ClassElement classElement = declaration;
do {
if (seen.contains(classElement)) return;
seen.add(classElement);
@@ -1473,6 +1564,15 @@ class ClassElement extends ScopeContainerElement
f(classElement, element);
}
}
+ if (includeInjectedMembers) {
+ if (classElement.patch != null) {
+ for (Element element in classElement.patch.localMembers.reverse()) {
+ if (!element.isPatch) {
+ f(classElement, element);
+ }
+ }
+ }
+ }
classElement = includeSuperMembers ? classElement.superclass : null;
} while(classElement !== null);
}
@@ -1486,6 +1586,9 @@ class ClassElement extends ScopeContainerElement
* When [includeBackendMembers] and [includeSuperMembers] are both [:true:]
* then the fields are visited in the same order as they need to be given
* to the JavaScript constructor.
+ *
+ * When called on the implementation element both the fields declared in the
+ * origin and in the patch are included.
*/
void forEachInstanceField([void f(ClassElement enclosingClass, Element field),
includeBackendMembers = false,
@@ -1528,8 +1631,27 @@ class ClassElement extends ScopeContainerElement
bool isNative() => nativeName != null;
int hashCode() => id;
- Scope buildScope() =>
- new ClassScope(enclosingElement.buildScope(), this);
+ // TODO(johnniwinther): Rewrite to avoid the optional argument.
+ Scope buildScope({bool patchScope: false}) {
+ if (origin !== null) {
+ return new PatchClassScope(
+ enclosingElement.buildScope(patchScope: patchScope), origin, this);
+ } else if (patchScope && patch !== null) {
+ return new PatchClassScope(
+ enclosingElement.buildScope(patchScope: patchScope), this, patch);
+ } else {
+ return new ClassScope(
+ enclosingElement.buildScope(patchScope: patchScope), this);
+ }
+ }
+
+ Scope buildLocalScope() {
+ if (origin !== null) {
+ return new LocalPatchClassScope(origin, this);
+ } else {
+ return new LocalClassScope(this);
+ }
+ }
ClassElement cloneTo(Element enclosing, DiagnosticListener listener) {
listener.internalErrorOnElement(this, 'unsupported operation');
@@ -1538,6 +1660,16 @@ class ClassElement extends ScopeContainerElement
Link<DartType> get allSupertypesAndSelf {
return allSupertypes.prepend(new InterfaceType(this));
}
+
+ String toString() {
+ if (origin !== null) {
+ return 'patch ${super.toString()}';
+ } else if (patch !== null) {
+ return 'origin ${super.toString()}';
+ } else {
+ return super.toString();
+ }
+ }
}
class Elements {

Powered by Google App Engine
This is Rietveld 408576698