Index: sdk/lib/_internal/compiler/implementation/elements/modelx.dart |
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart |
index 4a5ffb7e3a9c9c97c3ad625166ad4563de32c19f..7fb55a09ead40268987361e04e6d96917dea9a1e 100644 |
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart |
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart |
@@ -5,6 +5,7 @@ |
library elements.modelx; |
import 'elements.dart'; |
+import '../helpers/helpers.dart'; |
import '../tree/tree.dart'; |
import '../util/util.dart'; |
import '../resolution/resolution.dart'; |
@@ -110,59 +111,17 @@ abstract class ElementX implements Element { |
/** See [WarnOnUseElement] for documentation. */ |
bool isWarnOnUse() => false; |
- /** |
- * Is [:true:] if this element has a corresponding patch. |
- * |
- * If [:true:] this element has a non-null [patch] field. |
- * |
- * See [:patch_parser.dart:] for a description of the terminology. |
- */ |
bool get isPatched => false; |
- /** |
- * Is [:true:] if this element is a patch. |
- * |
- * If [:true:] this element has a non-null [origin] field. |
- * |
- * See [:patch_parser.dart:] for a description of the terminology. |
- */ |
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 => !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 => !isPatch; |
+ bool get isImplementation => true; |
- bool get isSynthesized => false; |
+ bool get isDeclaration => true; |
- bool get isForwardingConstructor => false; |
+ Element get implementation => this; |
- bool get isMixinApplication => false; |
- |
- /** |
- * Returns the element which defines the implementation for the entity of this |
- * element. |
- * |
- * See [:patch_parser.dart:] for a description of the terminology. |
- */ |
- 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 => isPatch ? origin : this; |
+ Element get declaration => this; |
Element get patch { |
throw new UnsupportedError('patch is not supported on $this'); |
@@ -172,6 +131,12 @@ abstract class ElementX implements Element { |
throw new UnsupportedError('origin is not supported on $this'); |
} |
+ bool get isSynthesized => false; |
+ |
+ bool get isForwardingConstructor => false; |
+ |
+ bool get isMixinApplication => false; |
+ |
// TODO(johnniwinther): This breaks for libraries (for which enclosing |
// elements are null) and is invalid for top level variable declarations for |
// which the enclosing element is a VariableDeclarations and not a compilation |
@@ -350,15 +315,9 @@ class ErroneousElementX extends ElementX implements ErroneousElement { |
bool get isRedirectingFactory => unsupported(); |
- setPatch(patch) => unsupported(); |
computeSignature(compiler) => unsupported(); |
- requiredParameterCount(compiler) => unsupported(); |
- optionalParameterCount(compiler) => unsupported(); |
- parameterCount(compiler) => unsupported(); |
// TODO(kasperl): These seem unnecessary. |
- set patch(value) => unsupported(); |
- set origin(value) => unsupported(); |
set defaultImplementation(value) => unsupported(); |
get redirectionTarget => this; |
@@ -769,7 +728,8 @@ class ImportScope { |
Element operator [](String name) => importScope[name]; |
} |
-class LibraryElementX extends ElementX with AnalyzableElement |
+class LibraryElementX |
+ extends ElementX with AnalyzableElement, PatchMixin<LibraryElementX> |
implements LibraryElement { |
final Uri canonicalUri; |
CompilationUnitElement entryCompilationUnit; |
@@ -782,20 +742,6 @@ class LibraryElementX extends ElementX with AnalyzableElement |
final ScopeX localScope = new ScopeX(); |
final ImportScope importScope = new ImportScope(); |
- /** |
- * If this library is patched, [patch] points to the patch library. |
- * |
- * See [:patch_parser.dart:] for a description of the terminology. |
- */ |
- LibraryElementX 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 LibraryElementX origin; |
- |
/// A mapping from an imported element to the "import" tag. |
final Importers importers = new Importers(); |
@@ -812,22 +758,17 @@ class LibraryElementX extends ElementX with AnalyzableElement |
final Map<LibraryDependency, LibraryElement> tagMapping = |
new Map<LibraryDependency, LibraryElement>(); |
- LibraryElementX(Script script, [Uri canonicalUri, LibraryElement this.origin]) |
+ LibraryElementX(Script script, |
+ [Uri canonicalUri, LibraryElementX origin]) |
: this.canonicalUri = |
((canonicalUri == null) ? script.readableUri : canonicalUri), |
super(script.name, ElementKind.LIBRARY, null) { |
entryCompilationUnit = new CompilationUnitElementX(script, this); |
- if (isPatch) { |
- origin.patch = this; |
+ if (origin != null) { |
+ origin.applyPatch(this); |
} |
} |
- bool get isPatched => patch != null; |
- bool get isPatch => origin != null; |
- |
- LibraryElement get declaration => super.declaration; |
- LibraryElement get implementation => super.implementation; |
- |
Link<MetadataAnnotation> get metadata { |
return (libraryTag == null) ? super.metadata : libraryTag.metadata; |
} |
@@ -858,7 +799,8 @@ class LibraryElementX extends ElementX with AnalyzableElement |
* Adds [element] to the import scope of this library. |
* |
* If an element by the same name is already in the imported scope, an |
- * [ErroneousElement] will be put in the imported scope, allowing for detection of ambiguous uses of imported names. |
+ * [ErroneousElement] will be put in the imported scope, allowing for |
+ * detection of ambiguous uses of imported names. |
*/ |
void addImport(Element element, Import import, DiagnosticListener listener) { |
importScope.addImport(this, element, import, listener); |
@@ -1034,6 +976,10 @@ class LibraryElementX extends ElementX with AnalyzableElement |
} |
accept(ElementVisitor visitor) => visitor.visitLibraryElement(this); |
+ |
+ // TODO(johnniwinther): Remove these when issue 18630 is fixed. |
+ LibraryElementX get patch => super.patch; |
+ LibraryElementX get origin => super.origin; |
} |
class PrefixElementX extends ElementX implements PrefixElement { |
@@ -1284,7 +1230,8 @@ class FieldParameterElementX extends ParameterElementX |
/// patched with the corresponding parameter of the patch method. This is done |
/// to ensure that default values on parameters are computed once (on the |
/// origin parameter) but can be found through both the origin and the patch. |
-class ParameterElementX extends ElementX implements ParameterElement { |
+class ParameterElementX extends ElementX with PatchMixin<ParameterElement> |
+ implements ParameterElement { |
final VariableDefinitions definitions; |
final Identifier identifier; |
final Expression initializer; |
@@ -1334,12 +1281,6 @@ class ParameterElementX extends ElementX implements ParameterElement { |
FunctionType get functionType => type; |
accept(ElementVisitor visitor) => visitor.visitVariableElement(this); |
- |
- ParameterElementX patch = null; |
- ParameterElementX origin = null; |
- |
- bool get isPatch => origin != null; |
- bool get isPatched => patch != null; |
} |
class AbstractFieldElementX extends ElementX implements AbstractFieldElement { |
@@ -1486,7 +1427,8 @@ class FunctionSignatureX implements FunctionSignature { |
} |
} |
-class FunctionElementX extends ElementX with AnalyzableElement |
+class FunctionElementX |
+ extends ElementX with AnalyzableElement, PatchMixin<FunctionElement> |
implements FunctionElement { |
FunctionExpression cachedNode; |
DartType typeCache; |
@@ -1496,14 +1438,6 @@ class FunctionElementX extends ElementX with AnalyzableElement |
FunctionSignature functionSignatureCache; |
- /** |
- * A function declaration that should be parsed instead of the current one. |
- * The patch should be parsed as if it was in the current scope. Its |
- * signature must match this function's signature. |
- */ |
- FunctionElement patch = null; |
- FunctionElement origin = null; |
- |
final bool _hasNoBody; |
AbstractFieldElement abstractField; |
@@ -1545,9 +1479,6 @@ class FunctionElementX extends ElementX with AnalyzableElement |
defaultImplementation = this; |
} |
- bool get isPatched => patch != null; |
- bool get isPatch => origin != null; |
- |
bool get isRedirectingFactory => defaultImplementation != this; |
/// This field is set by the post process queue when checking for cycles. |
@@ -1575,18 +1506,6 @@ class FunctionElementX extends ElementX with AnalyzableElement |
return redirectionTargetType.substByContext(newType); |
} |
- /** |
- * Applies a patch function to this function. The patch function's body |
- * is used as replacement when parsing this function's body. |
- * This method must not be called after the function has been parsed, |
- * and it must be called at most once. |
- */ |
- void setPatch(FunctionElement patchElement) { |
- // Sanity checks. The caller must check these things before calling. |
- assert(patch == null); |
- this.patch = patchElement; |
- } |
- |
bool isInstanceMember() { |
return isMember() |
&& !isConstructor() |
@@ -1911,6 +1830,7 @@ abstract class TypeDeclarationElementX<T extends GenericType> |
abstract class BaseClassElementX extends ElementX |
with AnalyzableElement, |
TypeDeclarationElementX<InterfaceType>, |
+ PatchMixin<ClassElement>, |
ClassMemberMixin |
implements ClassElement { |
final int id; |
@@ -1943,10 +1863,6 @@ abstract class BaseClassElementX extends ElementX |
super(name, ElementKind.CLASS, enclosing); |
int get hashCode => id; |
- ClassElement get patch => super.patch; |
- ClassElement get origin => super.origin; |
- ClassElement get declaration => super.declaration; |
- ClassElement get implementation => super.implementation; |
bool get hasBackendMembers => !backendMembers.isEmpty; |
@@ -2297,13 +2213,13 @@ abstract class BaseClassElementX extends ElementX |
lookupInterfaceMember(const PublicName(Compiler.CALL_OPERATOR_NAME)); |
return member != null && member.isMethod ? member.type : null; |
} |
+ |
+ // TODO(johnniwinther): Remove these when issue 18630 is fixed. |
+ ClassElement get patch => super.patch; |
+ ClassElement get origin => super.origin; |
} |
abstract class ClassElementX extends BaseClassElementX { |
- // Lazily applied patch of class members. |
- ClassElement patch = null; |
- ClassElement origin = null; |
- |
Link<Element> localMembers = const Link<Element>(); |
final ScopeX localScope = new ScopeX(); |
@@ -2313,8 +2229,6 @@ abstract class ClassElementX extends BaseClassElementX { |
ClassNode parseNode(Compiler compiler); |
bool get isMixinApplication => false; |
- bool get isPatched => patch != null; |
- bool get isPatch => origin != null; |
bool get hasLocalScopeMembers => !localScope.isEmpty; |
void addMember(Element element, DiagnosticListener listener) { |
@@ -2393,16 +2307,9 @@ class MixinApplicationElementX extends BaseClassElementX |
bool get hasConstructor => !constructors.isEmpty; |
bool get hasLocalScopeMembers => !constructors.isEmpty; |
- unsupported(message) { |
- throw new UnsupportedError('$message is not supported on $this'); |
- } |
- |
get patch => null; |
get origin => null; |
- set patch(value) => unsupported('set patch'); |
- set origin(value) => unsupported('set origin'); |
- |
Token position() => node.getBeginToken(); |
Node parseNode(DiagnosticListener listener) => node; |
@@ -2626,3 +2533,34 @@ class ParameterMetadataAnnotation extends MetadataAnnotationX { |
Token get endToken => metadata.getEndToken(); |
} |
+/// Mixin for the implementation of patched elements. |
+/// |
+/// See [:patch_parser.dart:] for a description of the terminology. |
+abstract class PatchMixin<E extends Element> implements Element { |
+ // TODO(johnniwinther): Use type variables when issue 18630 is fixed. |
+ Element/*E*/ patch = null; |
+ Element/*E*/ origin = null; |
+ |
+ bool get isPatch => origin != null; |
+ bool get isPatched => patch != null; |
+ |
+ bool get isImplementation => !isPatched; |
+ bool get isDeclaration => !isPatch; |
+ |
+ Element/*E*/ get implementation => isPatched ? patch : this; |
+ Element/*E*/ get declaration => isPatch ? origin : this; |
+ |
+ /// Applies a patch to this element. This method must be called at most once. |
+ void applyPatch(PatchMixin<E> patch) { |
+ assert(invariant(this, this.patch == null, |
+ message: "Element is patched twice.")); |
+ assert(invariant(this, this.origin == null, |
+ message: "Origin element is a patch.")); |
+ assert(invariant(patch, patch.origin == null, |
+ message: "Element is patched twice.")); |
+ assert(invariant(patch, patch.patch == null, |
+ message: "Patch element is patched.")); |
+ this.patch = patch; |
+ patch.origin = this; |
+ } |
+} |